feat: adicionei inglês.
This commit is contained in:
parent
311efcae62
commit
6301e33686
129
Content/DevTutoriais/formatos-de-imagem.en.md
Normal file
129
Content/DevTutoriais/formatos-de-imagem.en.md
Normal file
@ -0,0 +1,129 @@
|
||||
---
|
||||
title: "PNG, WebP or SVG? Choosing the Right Format for Your QR Code"
|
||||
description: "Technical comparison between PNG, WebP and SVG for QR codes via API. Learn which format to use depending on your use case: email, printing, web or apps."
|
||||
keywords: "qr code png, qr code webp, qr code svg, qr code image format, api qr code format"
|
||||
author: "QRRapido"
|
||||
date: 2026-03-08
|
||||
lastmod: 2026-03-08
|
||||
image: ""
|
||||
---
|
||||
|
||||
# PNG, WebP or SVG? Choosing the Right Format for Your QR Code
|
||||
|
||||
The QRRapido API supports three output formats: `png`, `webp` and `svg`. Each has distinct characteristics that impact file size, quality and compatibility. Use the `outputFormat` parameter in the request to choose.
|
||||
|
||||
```json
|
||||
{
|
||||
"content": "https://yoursite.com",
|
||||
"type": "url",
|
||||
"outputFormat": "webp"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Summary
|
||||
|
||||
| Format | Size | Lossless scaling | Compatibility | Ideal for |
|
||||
|---|---|---|---|---|
|
||||
| **PNG** | Medium | No (raster) | Universal | Printing, email, legacy |
|
||||
| **WebP** | Small (~30% smaller) | No (raster) | Modern browsers | Web, apps, APIs |
|
||||
| **SVG** | Variable (usually smaller) | **Yes** | Browsers, Adobe, Figma | Logos, banners, vector printing |
|
||||
|
||||
---
|
||||
|
||||
## PNG — The Universal Standard
|
||||
|
||||
PNG is a lossless raster format, ideal for QR codes because it preserves 100% of the black and white pixels without introducing artifacts.
|
||||
|
||||
**When to use:**
|
||||
- Sending by email (legacy email clients don't support WebP)
|
||||
- Integration with legacy systems
|
||||
- When maximum compatibility is a priority
|
||||
|
||||
**Why not JPEG?**
|
||||
|
||||
> JPEG uses lossy compression that introduces blur artifacts on the edges of QR code modules. This can make the code unreadable, especially at smaller sizes. **Never use JPEG for QR codes.**
|
||||
|
||||
```json
|
||||
{ "outputFormat": "png" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## WebP — Recommended for Web and Apps
|
||||
|
||||
WebP is the ideal format for most modern integrations. Visual quality is indistinguishable from PNG for QR codes, with **25–35% smaller file size**.
|
||||
|
||||
**Advantages:**
|
||||
- Faster loading on web pages
|
||||
- Lower bandwidth usage in APIs with high volume
|
||||
- Native support in all modern browsers (Chrome, Safari 14+, Firefox, Edge)
|
||||
- Lower storage consumption in buckets (S3, GCS, etc.)
|
||||
|
||||
**When to use:**
|
||||
- Display in `<img>` on websites and web applications
|
||||
- iOS/Android apps (both support WebP)
|
||||
- When you store the generated QR codes
|
||||
|
||||
```json
|
||||
{ "outputFormat": "webp" }
|
||||
```
|
||||
|
||||
To display in HTML:
|
||||
```html
|
||||
<picture>
|
||||
<source srcset="data:image/webp;base64,{{ qrCodeBase64 }}" type="image/webp">
|
||||
<img src="data:image/png;base64,{{ fallbackBase64 }}" alt="QR Code">
|
||||
</picture>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SVG — For Lossless Scaling
|
||||
|
||||
SVG is a vector format: the QR code is described mathematically, not as pixels. This means it can be resized to any size — from a 16px icon to a 3-meter banner — without loss of quality.
|
||||
|
||||
**When to use:**
|
||||
- Graphic materials (banners, posters, packaging, merchandise)
|
||||
- Integration with design tools (Figma, Illustrator, Canva)
|
||||
- High-quality printing without depending on resolution
|
||||
|
||||
**Caution:**
|
||||
- Do not use SVG for email sending (most email clients block SVG for security reasons)
|
||||
- Some older QR readers may have difficulty with SVG rendered directly via `<img>`
|
||||
|
||||
```json
|
||||
{ "outputFormat": "svg" }
|
||||
```
|
||||
|
||||
To display SVG inline, the `qrCodeBase64` must be decoded first:
|
||||
```js
|
||||
const svgString = atob(qrCodeBase64);
|
||||
document.getElementById('qr').innerHTML = svgString;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Size Comparison (real example — 400px, simple URL)
|
||||
|
||||
| Format | Typical size |
|
||||
|---|---|
|
||||
| PNG | ~8–12 KB |
|
||||
| WebP | ~5–8 KB |
|
||||
| SVG | ~3–6 KB |
|
||||
|
||||
> Sizes vary depending on content complexity (QR codes with more data have more modules).
|
||||
|
||||
---
|
||||
|
||||
## Recommendation by Use Case
|
||||
|
||||
| Scenario | Recommended format |
|
||||
|---|---|
|
||||
| Display on website/app | **WebP** |
|
||||
| Send by email | **PNG** |
|
||||
| Graphic printing / design | **SVG** |
|
||||
| Store in cloud | **WebP** |
|
||||
| Maximum compatibility | **PNG** |
|
||||
| No concern about size | **PNG** |
|
||||
186
Content/DevTutoriais/gerando-qrcodes-pela-api.en.md
Normal file
186
Content/DevTutoriais/gerando-qrcodes-pela-api.en.md
Normal file
@ -0,0 +1,186 @@
|
||||
---
|
||||
title: "How to Generate QR Codes via API: All Supported Types"
|
||||
description: "Complete guide to generating QR codes via REST API using each available type: URL, Pix, Wi-Fi, vCard, WhatsApp, SMS, email and free text."
|
||||
keywords: "api qr code, generate qr code api, qr code rest api, qrrapido api, qr code types"
|
||||
author: "QRRapido"
|
||||
date: 2026-03-08
|
||||
lastmod: 2026-03-08
|
||||
image: ""
|
||||
---
|
||||
|
||||
# How to Generate QR Codes via API: All Supported Types
|
||||
|
||||
The QRRapido API supports 8 QR code types. All use the same endpoint — the only difference is the `type` field and the specific fields that make up the `content`.
|
||||
|
||||
## Endpoint
|
||||
|
||||
```
|
||||
POST /api/v1/QRManager/generate
|
||||
X-API-Key: your_key_here
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
## Base Request Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"content": "...",
|
||||
"type": "url",
|
||||
"size": 400,
|
||||
"primaryColor": "#000000",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"outputFormat": "png"
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `content` | string | required | QR code content |
|
||||
| `type` | string | `"url"` | QR code type (see below) |
|
||||
| `size` | int | `300` | Size in pixels (100–2000) |
|
||||
| `primaryColor` | string | `"#000000"` | Module color (hex) |
|
||||
| `backgroundColor` | string | `"#FFFFFF"` | Background color (hex) |
|
||||
| `outputFormat` | string | `"png"` | Format: `png`, `webp`, `svg` |
|
||||
|
||||
---
|
||||
|
||||
## Type `url` — Link / URL
|
||||
|
||||
The simplest: any valid URL.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "url",
|
||||
"content": "https://yoursite.com/product/123"
|
||||
}
|
||||
```
|
||||
|
||||
> Use `https://` whenever possible. QR codes with HTTP may be blocked by some modern readers.
|
||||
|
||||
---
|
||||
|
||||
## Type `pix` — Pix Payment
|
||||
|
||||
The `content` must be the **Pix key** of the recipient. The generation produces a static Pix QR code (without connection to the Central Bank — see the dedicated Pix tutorial).
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "pix",
|
||||
"content": "contact@yourcompany.com"
|
||||
}
|
||||
```
|
||||
|
||||
Accepted keys: CPF/CNPJ (digits only), email, phone in `+5511999999999` format, or random key (UUID).
|
||||
|
||||
---
|
||||
|
||||
## Type `wifi` — Wi-Fi Network
|
||||
|
||||
The `content` uses the standard `WIFI:` format:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "wifi",
|
||||
"content": "WIFI:S:NetworkName;T:WPA;P:NetworkPassword;;"
|
||||
}
|
||||
```
|
||||
|
||||
| Parameter | Meaning | Values |
|
||||
|---|---|---|
|
||||
| `S:` | SSID (network name) | text |
|
||||
| `T:` | Security type | `WPA`, `WEP`, `nopass` |
|
||||
| `P:` | Password | text |
|
||||
| `H:` | Hidden network (optional) | `true` / `false` |
|
||||
|
||||
---
|
||||
|
||||
## Type `vcard` — Business Card
|
||||
|
||||
The `content` must be a complete vCard v3:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "vcard",
|
||||
"content": "BEGIN:VCARD\nVERSION:3.0\nFN:John Smith\nORG:Company Inc\nTEL:+15559876543\nEMAIL:john@company.com\nURL:https://company.com\nEND:VCARD"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Type `whatsapp` — WhatsApp Link
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "whatsapp",
|
||||
"content": "https://wa.me/15559876543?text=Hi%2C%20I%27d%20like%20to%20know%20more"
|
||||
}
|
||||
```
|
||||
|
||||
The number must include country code and area code, without spaces or symbols. The `text` parameter is optional.
|
||||
|
||||
---
|
||||
|
||||
## Type `email` — Email with subject and body
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "email",
|
||||
"content": "mailto:contact@company.com?subject=Subject&body=Initial%20message"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Type `sms` — Pre-filled SMS
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "sms",
|
||||
"content": "sms:+15559876543?body=Hi%2C%20I%20want%20more%20information"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Type `texto` — Free Text
|
||||
|
||||
Any string up to 2048 characters:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "texto",
|
||||
"content": "Table 12 — Priority service available at the main counter."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Success Response
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"qrCodeBase64": "iVBORw0KGgo...",
|
||||
"qrId": "abc123",
|
||||
"generationTimeMs": 180,
|
||||
"remainingCredits": 42,
|
||||
"fromCache": false,
|
||||
"format": "png",
|
||||
"mimeType": "image/png"
|
||||
}
|
||||
```
|
||||
|
||||
To display the image directly in HTML:
|
||||
|
||||
```html
|
||||
<img src="data:image/png;base64,{{ qrCodeBase64 }}" alt="QR Code" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## General Tips
|
||||
|
||||
- **Colors**: maintain high contrast between `primaryColor` and `backgroundColor`. Avoid yellow on white or light gray on white.
|
||||
- **Minimum printed size**: use `size` ≥ 400 for printing. For digital use (screens), 300 is sufficient.
|
||||
- **Cache**: identical requests return `fromCache: true` without consuming additional credit.
|
||||
- **Rate limit**: the `X-RateLimit-Remaining` and `X-Quota-Remaining` headers in the response indicate your current balance.
|
||||
142
Content/DevTutoriais/qr-code-pix-estatico.en.md
Normal file
142
Content/DevTutoriais/qr-code-pix-estatico.en.md
Normal file
@ -0,0 +1,142 @@
|
||||
---
|
||||
title: "Static Pix QR Code: How It Works and Developer Responsibilities"
|
||||
description: "Understand what a static Pix QR Code is, how it is generated by the API, its limitations, and why payment verification is your application's responsibility — not QRRapido's."
|
||||
keywords: "pix qr code, static pix, pix qr code api, pix qr code integration, pix without central bank"
|
||||
author: "QRRapido"
|
||||
date: 2026-03-08
|
||||
lastmod: 2026-03-08
|
||||
image: ""
|
||||
---
|
||||
|
||||
# Static Pix QR Code: How It Works and Developer Responsibilities
|
||||
|
||||
## What is a Static Pix QR Code?
|
||||
|
||||
Pix has two types of QR codes: **static** and **dynamic**.
|
||||
|
||||
| | Static Pix | Dynamic Pix |
|
||||
|---|---|---|
|
||||
| Amount | Variable (payer decides) | Fixed (set by recipient) |
|
||||
| Generation | Any system | PSP/Central Bank intermediary |
|
||||
| Central Bank registration | **No** | Yes |
|
||||
| Payment notification | **No** | Yes (webhook) |
|
||||
| Typical use | Donations, simple charges | E-commerce, tracked billing |
|
||||
|
||||
The QRRapido API generates **exclusively static Pix QR codes**. This is deliberate and sufficient for most use cases.
|
||||
|
||||
---
|
||||
|
||||
## How the API Generates the Pix QR Code
|
||||
|
||||
When you send a request with `type: "pix"`, the API assembles a string in the **EMV® QR Code** standard (the international standard adopted by Brazil's Central Bank) and generates the image:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "pix",
|
||||
"content": "contact@yourcompany.com"
|
||||
}
|
||||
```
|
||||
|
||||
The `content` field must contain **only the Pix key** of the recipient. The API handles assembling the EMV payload correctly.
|
||||
|
||||
**Accepted keys:**
|
||||
- Email: `contact@company.com`
|
||||
- CPF/CNPJ: digits only — `12345678901` or `12345678000195`
|
||||
- Phone: `+5511999999999`
|
||||
- Random key (EVP): `123e4567-e89b-12d3-a456-426614174000`
|
||||
|
||||
---
|
||||
|
||||
## What the API Does NOT Do (and Why This Matters)
|
||||
|
||||
> **QRRapido has no integration with the Central Bank, any bank, or any PSP (Payment Service Provider).**
|
||||
|
||||
This means:
|
||||
|
||||
1. **The API does not know if the payment was made.** It only generates the QR code image. What happens after — whether the customer scanned it, whether the Pix was sent, whether it landed in the right account — is outside the scope of the API.
|
||||
|
||||
2. **There is no payment confirmation webhook.** The API does not send notifications when a Pix is received.
|
||||
|
||||
3. **The QR code does not expire automatically.** A static Pix QR code is valid indefinitely (or until the Pix key is removed by the recipient at the bank).
|
||||
|
||||
4. **There is no transaction traceability.** Two requests with the same key generate the same QR code (with cache). It is not possible to associate a scan with a specific transaction via the API.
|
||||
|
||||
---
|
||||
|
||||
## Your Application's Responsibility
|
||||
|
||||
If you use the API to generate Pix QR codes in a payment flow, **it is your application's responsibility to verify receipt**. The correct ways to do this are:
|
||||
|
||||
### Option 1 — Recipient's Bank Pix API
|
||||
Connect directly to the Pix API of the bank where the key is registered. Most banks offer:
|
||||
- Query of received charges
|
||||
- Real-time notification webhook (when the bank supports it)
|
||||
|
||||
### Option 2 — PSP / Payment Gateway
|
||||
Use an intermediary such as Mercado Pago, PagSeguro, Efí Bank, Asaas, etc. They offer dynamic Pix with full control: fixed amount, expiration, webhooks and unique identification per charge.
|
||||
|
||||
### Option 3 — Manual Verification
|
||||
For low volumes or informal contexts (donations, in-person sales), the person responsible for receiving verifies the bank statement manually.
|
||||
|
||||
---
|
||||
|
||||
## Recommended Flow (with confirmation)
|
||||
|
||||
```
|
||||
Your App QRRapido API Recipient's Bank
|
||||
| | |
|
||||
|-- POST /generate (pix) -->| |
|
||||
|<-- qrCodeBase64 ----------| |
|
||||
| | |
|
||||
|-- Shows QR to customer | |
|
||||
| | |
|
||||
|-- Query payment ---------------------------------->|
|
||||
|<-- Received status or not --------------------------|
|
||||
| | |
|
||||
|-- Releases product/service| |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Request Example
|
||||
|
||||
```bash
|
||||
curl -X POST https://qrrapido.site/api/v1/QRManager/generate \
|
||||
-H "X-API-Key: your_key_here" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"content": "contact@yourcompany.com",
|
||||
"type": "pix",
|
||||
"size": 400,
|
||||
"outputFormat": "webp"
|
||||
}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Appropriate Use Cases for Static Pix via API
|
||||
|
||||
- Donation QR code on an institutional website
|
||||
- Digital menu with key for in-person payment
|
||||
- Batch QR generation for printed materials (flyers, cards)
|
||||
- Applications where the seller and buyer interact in person and the seller confirms receipt in the bank app
|
||||
|
||||
## Use Cases That Require Dynamic Pix (not supported by this API)
|
||||
|
||||
- E-commerce with automatic order confirmation
|
||||
- Fixed-amount billing with expiration
|
||||
- Invoice issuance linked to payment
|
||||
- Automated financial reconciliation
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| What the API does | What the API does NOT do |
|
||||
|---|---|
|
||||
| Generates the Pix QR code image | Verifies if the payment was made |
|
||||
| Formats the EMV payload correctly | Sends confirmation webhook |
|
||||
| Delivers PNG, WebP or SVG | Communicates with the Central Bank or banks |
|
||||
| Works with any valid Pix key | Guarantees the key belongs to who claims it does |
|
||||
|
||||
Correct QR code generation is the API's responsibility. **Payment confirmation is your application's responsibility.**
|
||||
89
Content/Tutoriais/como-criar-qr-code-pix.en.md
Normal file
89
Content/Tutoriais/como-criar-qr-code-pix.en.md
Normal file
@ -0,0 +1,89 @@
|
||||
---
|
||||
title: "How to Create a Static PIX QR Code"
|
||||
description: "Learn how to create a static PIX QR Code to receive instant payments easily and securely. Complete guide with QR Rapido."
|
||||
keywords: "pix qr code, generate pix qr code, static pix, create payment qr code, pix qr code free, pix qr code no fee"
|
||||
author: "QR Rapido"
|
||||
date: 2026-01-24
|
||||
lastmod: 2026-01-24
|
||||
image: "/images/tutoriais/pix-qr-hero.jpg"
|
||||
---
|
||||
|
||||
# How to Create a Static PIX QR Code: The Complete Guide
|
||||
|
||||
**PIX** revolutionized the way payments are made in Brazil. And for those who sell products or receive donations, the **PIX QR Code** is an essential tool. In this tutorial, you will learn how to generate a **Static PIX QR Code** for free using **QR Rapido**, ensuring speed and security in your transactions.
|
||||
|
||||
## 💸 What is a Static PIX QR Code?
|
||||
|
||||
The PIX Static QR Code is ideal for those who want to receive multiple payments of the same amount or varying amounts using a single code. It always "points" to the same bank account (your PIX key) and can contain additional information such as the recipient's name and city.
|
||||
|
||||
**Main advantages:**
|
||||
- **Does not expire:** Use the same code indefinitely.
|
||||
- **No fees:** Generation is free and does not depend on intermediaries (gateways).
|
||||
- **Versatile:** Can have a fixed value set or leave the amount open for the payer to fill in.
|
||||
- **Ideal for:** Merchants, freelancers, donations, crowdfunding and service providers.
|
||||
|
||||
## 🎯 Step by Step to Generate on QR Rapido
|
||||
|
||||
**QR Rapido** now has a native and secure tool to generate your PIX code. Follow the steps:
|
||||
|
||||
### 1. Access the Generator
|
||||
|
||||
Open [QR Rapido](https://qrrapido.site) and in the QR Code type menu, select the **"💸 PIX"** option.
|
||||
|
||||
### 2. Fill in the Required Data
|
||||
|
||||
For the code to work at any bank, the Central Bank standard requires three pieces of information:
|
||||
|
||||
- **PIX Key:** Can be your CPF, CNPJ, Email, Phone or Random Key.
|
||||
- **Beneficiary Name:** Your name or your company's name (must be the same as on the bank account).
|
||||
- **City:** The city where the account was opened or where you reside.
|
||||
|
||||
> **⚠️ Note:** Fill in the data exactly as registered at your bank to avoid errors during payment.
|
||||
|
||||
### 3. Set Amount and Description (Optional)
|
||||
|
||||
- **Amount:** If you sell a product with a fixed price (e.g., "Coffee $3.00"), fill in the amount field. If it's a donation or variable payment, leave it blank so the customer can enter the amount.
|
||||
- **Transaction ID (TxID):** An optional code to help you identify the payment in your statement (e.g., "ORDER01"). If not filled, the system will use the default `***`.
|
||||
- **Description:** A message that may appear on the payer's confirmation screen (e.g., "Service Payment").
|
||||
|
||||
### 4. Generate and Customize
|
||||
|
||||
Click **"Generate QR Code"**. You can customize the color and style (rounded corners, for example) to match your brand, but remember: **Keep high contrast** (preferably black on white) to ensure any phone can read it.
|
||||
|
||||
### 5. Download
|
||||
|
||||
Download the image in **PNG** for use on social media or **PDF/SVG** to print in high quality on signs and posters.
|
||||
|
||||
## 🏪 Tip for Merchants and Sellers
|
||||
|
||||
If you sell **many different products** and want to speed up payment at the checkout or on shelves, QR Rapido has the ideal solution:
|
||||
|
||||
> **Subscribe to our Monthly Plan!**
|
||||
> With the Premium plan, you can create and manage an **exclusive QR Code for each product** in your catalog. That way, the customer scans the specific product's code and the correct amount is already filled in, avoiding errors and speeding up the sale. [Learn more about the Premium plan](/Pagamento/SelecaoPlano).
|
||||
|
||||
## 💡 Professional Tips for Your PIX
|
||||
|
||||
### Print with Quality
|
||||
If you're going to place the QR Code on your store counter, print it at a readable size (at least 2" x 2"). Protect the paper with lamination or use an acrylic display.
|
||||
|
||||
### Test Before Distributing
|
||||
Before printing 1000 flyers or posting on Instagram, do a real test! Open your bank app, read the generated QR Code and transfer a symbolic amount to make sure the data is correct and the money goes to the right account.
|
||||
|
||||
### Security
|
||||
QR Rapido generates the code directly in your browser. We do **not** have access to your bank account and do **not** intermediate the money. The payment goes directly from the customer to your account.
|
||||
|
||||
## 🚀 Why use QR Rapido for PIX?
|
||||
|
||||
- **EMVCo Compliance:** We use the official international standard, guaranteeing compatibility with all major banking apps.
|
||||
- **Privacy:** Your sensitive data is not stored.
|
||||
- **Speed:** Generate your code in seconds, without lengthy registrations.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Having a PIX QR Code on hand speeds up service and conveys professionalism. With **QR Rapido**, you create yours for free, customize it and start receiving payments right away.
|
||||
|
||||
**Ready to receive payments?** [Generate your PIX QR Code now →](https://qrrapido.site)
|
||||
|
||||
---
|
||||
|
||||
*Questions about generation? [Contact us](https://qrrapido.site/en/Contact) or check our FAQ.*
|
||||
108
Content/Tutoriais/como-criar-qr-code-whatsapp.en.md
Normal file
108
Content/Tutoriais/como-criar-qr-code-whatsapp.en.md
Normal file
@ -0,0 +1,108 @@
|
||||
---
|
||||
title: "How to Create a QR Code for WhatsApp"
|
||||
description: "Learn how to create a WhatsApp QR Code that allows users to instantly start a conversation with you"
|
||||
keywords: "whatsapp qr code, qr code for whatsapp, create whatsapp qr code, whatsapp qr"
|
||||
author: "QR Rapido"
|
||||
date: 2025-10-08
|
||||
lastmod: 2025-10-08
|
||||
image: "/images/tutoriais/whatsapp-qr-hero.jpg"
|
||||
---
|
||||
|
||||
# How to Create a QR Code for WhatsApp
|
||||
|
||||
Creating a **WhatsApp QR Code** is one of the most efficient ways to facilitate direct contact with your customers, friends or followers. With a simple scan, anyone can instantly start a conversation with you without needing to save your number.
|
||||
|
||||
## 📱 Why use a QR Code for WhatsApp?
|
||||
|
||||
WhatsApp QR Codes are extremely useful for:
|
||||
|
||||
- **Businesses**: Facilitating customer service
|
||||
- **Freelancers**: Speeding up contact with potential clients
|
||||
- **Events**: Enabling quick networking
|
||||
- **Marketing**: Increasing conversion in campaigns
|
||||
|
||||
## 🎯 Step by Step
|
||||
|
||||
### 1. Prepare your number
|
||||
|
||||
First, you need to have your number in international format:
|
||||
|
||||
```
|
||||
1 555 987-6543
|
||||
```
|
||||
|
||||
Remove all spaces and dashes:
|
||||
|
||||
```
|
||||
15559876543
|
||||
```
|
||||
|
||||
### 2. Create the WhatsApp URL
|
||||
|
||||
The WhatsApp URL follows this pattern:
|
||||
|
||||
```
|
||||
https://wa.me/15559876543
|
||||
```
|
||||
|
||||
You can add a pre-defined message:
|
||||
|
||||
```
|
||||
https://wa.me/15559876543?text=Hi!%20I%20would%20like%20more%20information
|
||||
```
|
||||
|
||||
### 3. Generate the QR Code
|
||||
|
||||
Access [QR Rapido](https://qrrapido.site) and:
|
||||
|
||||
1. Select the **URL** type
|
||||
2. Paste the WhatsApp URL
|
||||
3. Customize the colors (optional)
|
||||
4. Click **Generate QR Code**
|
||||
5. Download in high quality
|
||||
|
||||
## 💡 Professional Tips
|
||||
|
||||
### Customize the Initial Message
|
||||
|
||||
Set up an automatic welcome message to improve the experience:
|
||||
|
||||
```
|
||||
https://wa.me/15559876543?text=Hi!%20I%20found%20you%20through%20your%20QR%20Code
|
||||
```
|
||||
|
||||
### Use on Printed Materials
|
||||
|
||||
- **Business cards**: Make instant contact easy
|
||||
- **Flyers and leaflets**: Increase engagement
|
||||
- **Packaging**: Offer direct customer support
|
||||
- **Banners**: At events and trade shows
|
||||
|
||||
### Monitor the Results
|
||||
|
||||
To track how many people scanned your QR Code, consider using a URL shortener with analytics before generating the QR Code.
|
||||
|
||||
## ⚠️ Important Cautions
|
||||
|
||||
1. **Test before printing**: Always scan to verify it works
|
||||
2. **Minimum size**: Keep at least 1.2" x 1.2" for easy reading
|
||||
3. **Adequate contrast**: Use colors that contrast well (black on white is ideal)
|
||||
4. **Clear message**: Indicate what the QR Code is for
|
||||
|
||||
## 🚀 Advantages of using QR Rapido
|
||||
|
||||
- ⚡ **Ultra-fast**: Generate in less than 1 second
|
||||
- 🎨 **Customizable**: Choose colors and styles
|
||||
- 📥 **High quality**: Download in PNG, SVG and PDF
|
||||
- 🔒 **Secure**: Your data is not stored
|
||||
- 💯 **Free**: up to 50 QR codes per day after login
|
||||
|
||||
## Conclusion
|
||||
|
||||
Creating a QR Code for WhatsApp is simple and can revolutionize the way you communicate with your audience. With QR Rapido, you have everything you need to create professional QR Codes in seconds.
|
||||
|
||||
**Ready to start?** [Create your QR Code now →](https://qrrapido.site/en)
|
||||
|
||||
---
|
||||
|
||||
*Have questions? [Contact us](https://qrrapido.site/en/Contact)!*
|
||||
179
Content/Tutoriais/como-criar-qr-code-wifi.en.md
Normal file
179
Content/Tutoriais/como-criar-qr-code-wifi.en.md
Normal file
@ -0,0 +1,179 @@
|
||||
---
|
||||
title: "How to Create a Free WiFi QR Code: Share Your Network in Seconds"
|
||||
description: "Learn how to create a free WiFi QR Code in a few clicks. Share your network password without typing with our fast and secure generator."
|
||||
keywords: "wifi qr code, create wifi qr code, free wifi qr code generator, wifi network qr code, share wifi password, free wifi qr code, how to make wifi qr code"
|
||||
author: "QR Rapido"
|
||||
date: 2025-10-10
|
||||
lastmod: 2025-10-10
|
||||
image: "/images/tutoriais/qr-code-wifi-hero.jpg"
|
||||
---
|
||||
|
||||
# How to Create a Free WiFi QR Code: Share Your Network in Seconds
|
||||
|
||||
Tired of typing long and complicated passwords every time a guest asks for your WiFi password? With a **WiFi QR Code**, you can share your network instantly! In this complete tutorial, you'll learn how to create a WiFi QR Code for free in less than 2 minutes.
|
||||
|
||||
## Why Use a QR Code for WiFi?
|
||||
|
||||
Sharing your WiFi network through a QR Code offers several advantages:
|
||||
|
||||
- **Convenience**: Guests connect instantly without typing passwords
|
||||
- **Security**: No need to say the password out loud or write it down
|
||||
- **Professionalism**: Ideal for businesses, cafes, restaurants and offices
|
||||
- **Time saving**: Eliminates typing errors and repeated requests
|
||||
- **Compatibility**: Works on virtually all modern smartphones
|
||||
|
||||
## Step by Step: How to Create Your WiFi QR Code
|
||||
|
||||
### Step 1: Select the QR Code Type
|
||||
|
||||
Access the generator and choose the **WiFi** option from the list of available QR Code types.
|
||||
|
||||
In the dropdown menu, you'll find various options like URL/Link, Plain Text, Business Card, SMS and Email. For this tutorial, select **WiFi**.
|
||||
|
||||
### Step 2: Fill in Your WiFi Network Details
|
||||
|
||||
Now you need to enter your network details. See the required fields:
|
||||
|
||||
#### NetworkName (Network Name) *
|
||||
Type exactly the name of your WiFi network (SSID). For example: "YourNetworkName"
|
||||
|
||||
**Important tip**: The name must be identical to what appears when you search for WiFi networks on your phone. It is case-sensitive!
|
||||
|
||||
#### SecurityType (Security Type)
|
||||
Select the encryption type of your network:
|
||||
|
||||
- **WPA Network (most common)**: WPA/WPA2/WPA3 - recommended and most secure
|
||||
- **WEP (very old)**: Not recommended as it is insecure
|
||||
- **No password**: For public networks without protection
|
||||
|
||||
#### NetworkPassword (Network Password) *
|
||||
Enter your WiFi network password. Use the eye icon to view and verify you typed it correctly.
|
||||
|
||||
**Important**: The password is also case-sensitive. Check it carefully!
|
||||
|
||||
#### HiddenNetwork (Hidden Network)
|
||||
Check this option only if your network is configured as hidden (does not appear in the list of available networks).
|
||||
|
||||
### Step 3: Customize Your QR Code (Optional)
|
||||
|
||||
Give your QR Code your business's look!
|
||||
|
||||
#### Customization Options:
|
||||
|
||||
**Primary Color**: Choose the color of the QR Code squares (default: black)
|
||||
|
||||
**Background Color**: Set the background color (default: white)
|
||||
|
||||
**Size**: Choose from:
|
||||
- Small (200px) - For digital use
|
||||
- Medium (300px) - Recommended for printing
|
||||
- Large (500px) - For banners and posters
|
||||
|
||||
**Margin**:
|
||||
- Compact - Takes up less space
|
||||
- Normal - Recommended (better readability)
|
||||
- Wide - For large prints
|
||||
|
||||
**Design tip**: Maintain good contrast between the primary color and background to ensure all phones can read the code.
|
||||
|
||||
### Step 4: Generate and Download
|
||||
|
||||
Click the **"⚡ Generate QR Code Quickly"** button and you're done! Your WiFi QR Code will be generated instantly.
|
||||
|
||||
You can:
|
||||
- Download the image in high quality
|
||||
- Print and place in visible locations
|
||||
- Share digitally
|
||||
- Save to use later
|
||||
|
||||
## How Your Guests Will Use the WiFi QR Code
|
||||
|
||||
It's very simple! Your guests just need to:
|
||||
|
||||
1. Open the phone camera (iOS or Android)
|
||||
2. Point at the QR Code
|
||||
3. Tap the notification that appears
|
||||
4. Connect automatically to the WiFi
|
||||
|
||||
**No app download needed!** Most smartphones since 2018 already have built-in QR Code readers in the camera.
|
||||
|
||||
## Where to Use Your WiFi QR Code
|
||||
|
||||
### For Businesses
|
||||
- Office reception areas
|
||||
- Meeting rooms
|
||||
- Waiting areas
|
||||
- Coworking spaces
|
||||
|
||||
### For Retail
|
||||
- Restaurant tables
|
||||
- Café counters
|
||||
- Stores and boutiques
|
||||
- Beauty salons
|
||||
|
||||
### For Homes
|
||||
- Entry hallway
|
||||
- Barbecue area
|
||||
- Refrigerator (for parties)
|
||||
- Home office
|
||||
|
||||
### For Events
|
||||
- Event credentials
|
||||
- Trade show booths
|
||||
- Conferences
|
||||
- Weddings and parties
|
||||
|
||||
## Security Tips
|
||||
|
||||
⚠️ **Important**: Consider creating a separate WiFi network for guests (guest network) if you want to:
|
||||
|
||||
- Protect your personal devices
|
||||
- Limit speed for guests
|
||||
- Have control over who accesses your network
|
||||
- Keep your main network private
|
||||
|
||||
Many modern routers allow you to easily create guest networks in the settings.
|
||||
|
||||
## Frequently Asked Questions (FAQ)
|
||||
|
||||
### Does the WiFi QR Code expire?
|
||||
No! The QR Code works indefinitely as long as the network data (name and password) remains the same.
|
||||
|
||||
### Does it work on iPhone and Android?
|
||||
Yes! It works on virtually all smartphones made after 2018 that have a camera.
|
||||
|
||||
### Can I create one for a 5GHz network?
|
||||
Yes! The process is exactly the same. Just use the correct 5GHz network name.
|
||||
|
||||
### Is it safe?
|
||||
Yes! The QR Code simply makes it easier to enter the data. It is just as safe as sharing the password verbally or in writing.
|
||||
|
||||
### Can I edit it after it's created?
|
||||
You cannot edit the QR Code after it's generated. If you change your WiFi password, you'll need to generate a new QR Code.
|
||||
|
||||
### How many people can use the same QR Code?
|
||||
Unlimited! There is no usage limit for the QR Code.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Creating a WiFi QR Code is quick, easy and completely free at QR Rapido! In less than 2 minutes you can:
|
||||
|
||||
✅ Generate your custom QR Code
|
||||
✅ Share your network effortlessly
|
||||
✅ Provide a better experience for guests
|
||||
✅ Demonstrate professionalism
|
||||
|
||||
**Try it now**: [Create my Free WiFi QR Code](/)
|
||||
|
||||
---
|
||||
|
||||
**Liked this tutorial?** Share it with friends who also want to make WiFi access easier! Also explore our other QR Code types for different needs.
|
||||
|
||||
## Other Useful Tutorials
|
||||
|
||||
- How to create a QR Code for WhatsApp
|
||||
- QR Code for Digital Business Cards
|
||||
- How to create a QR Code for URLs and Links
|
||||
- Advanced QR Code customization
|
||||
|
||||
**Create your free WiFi QR Code now and transform your guests' experience!** 🚀📱
|
||||
630
Content/Tutoriais/qr-code-para-corretores-imoveis.en.md
Normal file
630
Content/Tutoriais/qr-code-para-corretores-imoveis.en.md
Normal file
@ -0,0 +1,630 @@
|
||||
---
|
||||
title: "QR Code for Real Estate Agents: Complete Guide for Labels and Flyers"
|
||||
description: "Discover how to use QR Codes on adhesive labels, signs and real estate flyers. Increase your sales with free and professional technology."
|
||||
keywords: "qr code real estate agent, realtor label, real estate qr code, adhesive labels realtors, promote real estate agent, qr code for sale sign"
|
||||
author: "QR Rapido"
|
||||
date: 2025-10-10
|
||||
lastmod: 2025-10-10
|
||||
image: "/images/tutoriais/qr-code-corretor-imoveis-hero.jpg"
|
||||
---
|
||||
|
||||
# QR Code for Real Estate Agents: Complete Guide for Labels and Flyers
|
||||
|
||||
If you are a real estate agent, you know that **capturing qualified leads** is essential to closing deals. Imagine turning your "For Sale" signs, flyers and adhesive labels into interactive tools that connect clients directly to your WhatsApp, property listing or digital business card — all of this **for free** with QR Codes!
|
||||
|
||||
In this complete guide, you will learn how to create and apply professional QR Codes on real estate materials, increasing your conversions and standing out from the competition.
|
||||
|
||||
## Why Real Estate Agents Should Use QR Codes?
|
||||
|
||||
### **Proven Advantages**
|
||||
|
||||
- ✅ **24/7 Lead Generation**: Your sign works for you even while you sleep
|
||||
- ✅ **Instant Contact**: Client scans and is already on your WhatsApp
|
||||
- ✅ **Zero Typing**: Eliminates errors when noting numbers
|
||||
- ✅ **Tracking**: Know how many people were interested
|
||||
- ✅ **Professionalism**: Demonstrates modernity and innovation
|
||||
- ✅ **Zero Cost**: Generate unlimited QR Codes for free
|
||||
- ✅ **Virtual Tour**: Take the client inside the property virtually
|
||||
|
||||
### **Market Statistics**
|
||||
|
||||
According to real estate industry studies:
|
||||
- **78%** of buyers research properties on their phones
|
||||
- **65%** prefer contact via WhatsApp instead of a call
|
||||
- **43%** scan QR Codes on property signs when they see them
|
||||
- Agents who use QR Codes have **35% more monthly leads**
|
||||
|
||||
---
|
||||
|
||||
## Where to Apply QR Codes in Real Estate Marketing
|
||||
|
||||
### **1. "For Sale" and "For Rent" Signs**
|
||||
|
||||
**The most powerful use!** The sign in front of the property is seen by hundreds of people daily.
|
||||
|
||||
**What to put in the QR Code:**
|
||||
- Direct link to your WhatsApp
|
||||
- vCard with your complete contacts
|
||||
- 360° virtual tour of the property
|
||||
- Detailed property spec sheet (PDF)
|
||||
- Property video on YouTube
|
||||
|
||||
**Professional tip**: Add eye-catching text like:
|
||||
- "Scan and schedule your visit NOW"
|
||||
- "Virtual Tour - Point your camera here"
|
||||
- "Direct WhatsApp to the Agent"
|
||||
|
||||
### **2. Adhesive Labels and Tags**
|
||||
|
||||
Small labels (2"x2" to 4"x4") are perfect for:
|
||||
|
||||
**Applications:**
|
||||
- Sticking on agency cars
|
||||
- Fixing on property gates
|
||||
- Applying to store windows
|
||||
- Distributing at partner businesses
|
||||
- Placing in building elevators
|
||||
|
||||
**Advantages:**
|
||||
- Low printing cost
|
||||
- Easy mass distribution
|
||||
- Can be replaced quickly
|
||||
- Great for promotional actions
|
||||
|
||||
### **3. Flyers and Leaflets**
|
||||
|
||||
Transform paper flyers into digital tools!
|
||||
|
||||
**Where to apply:**
|
||||
- Top right corner (area of greatest attention)
|
||||
- Center, if it's the main focus
|
||||
- Back, with highlighted call to action
|
||||
|
||||
**Recommended content:**
|
||||
- Digital property portfolio
|
||||
- Registration form
|
||||
- Mortgage calculator
|
||||
- Complete list of available properties
|
||||
|
||||
### **4. Brochures and Real Estate Magazines**
|
||||
|
||||
Premium printed materials deserve strategic QR Codes.
|
||||
|
||||
**Ideal use:**
|
||||
- 1 QR per featured property
|
||||
- QR on the cover for the complete portfolio
|
||||
- QR on the back cover with your contacts
|
||||
- QR on each page with more information
|
||||
|
||||
### **5. Business Cards**
|
||||
|
||||
The classic never goes out of style, but can be enhanced!
|
||||
|
||||
**QR Code on the card allows:**
|
||||
- Save contact automatically (vCard)
|
||||
- View online portfolio
|
||||
- Schedule a meeting directly in the calendar
|
||||
- Send message via WhatsApp
|
||||
|
||||
### **6. Email Signature**
|
||||
|
||||
Every email you send is an opportunity!
|
||||
|
||||
**Include QR Code for:**
|
||||
- Your complete vCard
|
||||
- Latest property launch
|
||||
- Free property valuation
|
||||
- Scheduling visits
|
||||
|
||||
---
|
||||
|
||||
## Step by Step: How to Create QR Codes for Agents
|
||||
|
||||
Here's how to create **3 essential QR Code types** for real estate agents:
|
||||
|
||||
### **Type 1: vCard QR Code (Digital Business Card)**
|
||||
|
||||
Perfect for: Business cards, email signature, badges
|
||||
|
||||
#### Step 1: Select "Business Card"
|
||||
|
||||
Access the generator and choose the **Business Card** option from the type menu.
|
||||
|
||||
#### Step 2: Fill in Your Professional Data
|
||||
|
||||
**Required information:**
|
||||
- **Full name**: John Smith
|
||||
- **Title**: Real Estate Agent License #12345
|
||||
- **Company**: Success Real Estate
|
||||
- **Phone**: +1 555 987-6543
|
||||
- **Email**: john.smith@realestate.com
|
||||
- **Website**: www.johnsmith.realestate
|
||||
- **Address**: 1000 Main St - New York, NY
|
||||
|
||||
**Strategic optional fields:**
|
||||
- WhatsApp Business
|
||||
- Professional Instagram
|
||||
- LinkedIn
|
||||
- YouTube channel with virtual tours
|
||||
|
||||
#### Step 3: Generate and Download
|
||||
|
||||
Click **"Generate QR Code"** and download in high resolution.
|
||||
|
||||
**Where to use this QR:**
|
||||
- Adhesive labels on the car
|
||||
- Business cards
|
||||
- Email signature
|
||||
- Professional badge
|
||||
|
||||
---
|
||||
|
||||
### **Type 2: Direct WhatsApp QR Code**
|
||||
|
||||
Perfect for: Property signs, flyers, ads
|
||||
|
||||
#### Step 1: Select "WhatsApp"
|
||||
|
||||
In the generator, choose the **WhatsApp** option (or SMS if you prefer).
|
||||
|
||||
#### Step 2: Set Up the Pre-Written Message
|
||||
|
||||
**Example of an effective message:**
|
||||
|
||||
```
|
||||
Hi! I saw the property sign at [STREET/NEIGHBORHOOD] and would like to schedule a visit. Can you send me more information?
|
||||
```
|
||||
|
||||
**Why a pre-written message works:**
|
||||
- Client doesn't need to think about what to write
|
||||
- You already know which property they're talking about
|
||||
- Increases conversion rate by 80%
|
||||
|
||||
#### Step 3: Customize for Each Property
|
||||
|
||||
**Important tip**: Create different QR Codes for each property!
|
||||
|
||||
Example for a 3-bedroom apartment in downtown:
|
||||
```
|
||||
Hi! I saw the sign for the 3-bedroom Apartment downtown (Ref: APT-001). I'd like to know more details and schedule a visit.
|
||||
```
|
||||
|
||||
**Advantage**: You already know exactly which property the client wants to see!
|
||||
|
||||
---
|
||||
|
||||
### **Type 3: URL QR Code (Virtual Tour / Spec Sheet)**
|
||||
|
||||
Perfect for: High-end properties, launches, rural properties
|
||||
|
||||
#### Step 1: Prepare the Digital Content
|
||||
|
||||
Before creating the QR, you need to have:
|
||||
|
||||
**Option A - Virtual Tour:**
|
||||
- YouTube video of the property
|
||||
- 360° tour (Google Street View, Matterport)
|
||||
- Photo gallery on Instagram/Facebook
|
||||
|
||||
**Option B - Landing Page:**
|
||||
- Complete property spec sheet
|
||||
- High-resolution photos
|
||||
- Location map
|
||||
- Mortgage calculator
|
||||
- Interest registration form
|
||||
|
||||
#### Step 2: Shorten the URL (Important!)
|
||||
|
||||
Use URL shorteners like:
|
||||
- bit.ly
|
||||
- tinyurl.com
|
||||
|
||||
**Example:**
|
||||
- ❌ Long URL: `https://www.myrealestate.com/properties/3-bedroom-downtown-ref-apt001?utm_source=sign`
|
||||
- ✅ Short URL: `bit.ly/apt-downtown-001`
|
||||
|
||||
**Advantage of short URL**: Generates simpler QR Code that's easier to scan
|
||||
|
||||
#### Step 3: Create the QR Code
|
||||
|
||||
Paste the short URL into the **URL/Link** field and generate the code.
|
||||
|
||||
---
|
||||
|
||||
## How to Customize Your QR Code Professionally
|
||||
|
||||
### **Strategic Color Choices**
|
||||
|
||||
**For Traditional Real Estate Agencies:**
|
||||
- Navy blue + White (trust, seriousness)
|
||||
- Black + Gold (luxury, exclusivity)
|
||||
- Dark green + White (growth, stability)
|
||||
|
||||
**For Modern Real Estate Agencies:**
|
||||
- Orange + White (energy, innovation)
|
||||
- Purple + White (creativity, differentiation)
|
||||
- Red + White (urgency, action)
|
||||
|
||||
**Golden rule**: Always maintain high contrast between primary color and background!
|
||||
|
||||
### **Recommended Sizes by Application**
|
||||
|
||||
**Street signs (2-15 ft distance):**
|
||||
- QR Code: 6"x6" or larger
|
||||
- Resolution: 500px minimum
|
||||
|
||||
**Letter/A4 flyers:**
|
||||
- QR Code: 1.5"x1.5" to 2.5"x2.5"
|
||||
- Resolution: 300px
|
||||
|
||||
**Adhesive labels:**
|
||||
- QR Code: 2"x2" (sticker size)
|
||||
- Resolution: 300px
|
||||
|
||||
**Business cards:**
|
||||
- QR Code: 1"x1"
|
||||
- Resolution: 200px
|
||||
|
||||
### **Add Calls to Action (CTA)**
|
||||
|
||||
Never place a QR Code alone! Add attractive text:
|
||||
|
||||
**Effective examples:**
|
||||
- 📱 "Point your camera and message me on WhatsApp"
|
||||
- 🏠 "360° Virtual Tour - Scan Here"
|
||||
- 💬 "Schedule Your Visit Now"
|
||||
- 📋 "See Full Photos and Details"
|
||||
- 🎯 "Save My Contact Automatically"
|
||||
|
||||
---
|
||||
|
||||
## Advanced Strategies for Agents
|
||||
|
||||
### **1. Trackable (Dynamic) QR Codes**
|
||||
|
||||
Use dynamic QR Code services to:
|
||||
|
||||
- Know how many people scanned
|
||||
- See scan times
|
||||
- Identify approximate location
|
||||
- Change the destination without reprinting
|
||||
|
||||
**When to use:**
|
||||
- Campaigns with many printed materials
|
||||
- A/B testing different approaches
|
||||
- Permanent signs on properties
|
||||
|
||||
### **2. Multiple QR Codes on the Same Sign**
|
||||
|
||||
Large sign? Use 2-3 different QR Codes!
|
||||
|
||||
**Example of a complete sign:**
|
||||
- **QR 1** (top): "Message on WhatsApp"
|
||||
- **QR 2** (center): "360° Virtual Tour"
|
||||
- **QR 3** (bottom): "Save My Contact"
|
||||
|
||||
**Advantage**: Client chooses the action they prefer
|
||||
|
||||
### **3. QR Code + Augmented Reality**
|
||||
|
||||
For launches and developments:
|
||||
|
||||
- QR Code leads to AR app
|
||||
- Client points phone and sees the finished building
|
||||
- Views decorated apartment
|
||||
- Extremely impactful!
|
||||
|
||||
### **4. Seasonal Campaigns**
|
||||
|
||||
Create specific QR Codes for:
|
||||
|
||||
- **January**: "Plan the New Year - Buy Your Property"
|
||||
- **June**: "Summer Vacation in Your New Home"
|
||||
- **November**: "Black Friday Real Estate Sale"
|
||||
- **December**: "Start the Year in Your Own Home"
|
||||
|
||||
### **5. Strategic Partnerships**
|
||||
|
||||
Distribute labels with QR Code at:
|
||||
|
||||
- Building materials stores
|
||||
- Architecture offices
|
||||
- Notary offices
|
||||
- Neighborhood gyms and restaurants
|
||||
- Commercial buildings (bulletin boards)
|
||||
|
||||
---
|
||||
|
||||
## Professional Adhesive Label Templates
|
||||
|
||||
### **Template 1: Minimalist Label (2"x2")**
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ [QR CODE] │
|
||||
│ │
|
||||
│ John Smith │
|
||||
│ License #12345 │
|
||||
│ (555) 987-6543 │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
### **Template 2: Highlighted Label (3"x3")**
|
||||
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ SELL YOUR PROPERTY │
|
||||
│ HASSLE-FREE │
|
||||
│ │
|
||||
│ [QR CODE] │
|
||||
│ │
|
||||
│ "Scan and talk │
|
||||
│ directly to me" │
|
||||
│ │
|
||||
│ John Smith │
|
||||
│ Licensed Agent │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
### **Template 3: Virtual Tour Label (4"x4")**
|
||||
|
||||
```
|
||||
┌───────────────────────────┐
|
||||
│ 360° VIRTUAL TOUR │
|
||||
│ Visit this property │
|
||||
│ from your couch! │
|
||||
│ │
|
||||
│ [LARGE QR CODE] │
|
||||
│ │
|
||||
│ 📱 Point your camera │
|
||||
│ │
|
||||
│ Success Real Estate │
|
||||
│ (555) 987-6543 │
|
||||
└───────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Printing Practices
|
||||
|
||||
### **Recommended Materials**
|
||||
|
||||
**For outdoor signs:**
|
||||
- **UV-resistant vinyl**
|
||||
- **UV printed banner**
|
||||
- **ACM (Aluminum Composite)**
|
||||
|
||||
Durability: 2-3 years in direct sunlight
|
||||
|
||||
**For adhesive labels:**
|
||||
- **BOPP (Polypropylene) paper**
|
||||
- **Glossy white vinyl**
|
||||
- **Coated paper with lamination**
|
||||
|
||||
Durability: 6-12 months
|
||||
|
||||
**For flyers:**
|
||||
- **Coated 80lb or 100lb stock**
|
||||
- **Spot UV varnish on QR Code** (for emphasis)
|
||||
|
||||
### **Testing Before Mass Printing**
|
||||
|
||||
⚠️ **ALWAYS do this:**
|
||||
|
||||
1. Print 1 sample at actual size
|
||||
2. Test with 5 different phones
|
||||
3. Test at different distances
|
||||
4. Test in low light
|
||||
5. Only then print large quantities
|
||||
|
||||
**Phones to test:**
|
||||
- iPhone (updated iOS)
|
||||
- Samsung (Android)
|
||||
- Other Android brands (popular models)
|
||||
|
||||
### **Where to Print**
|
||||
|
||||
**Quick print shops:**
|
||||
- Adhesive labels: 100 units for $15-50
|
||||
- A5 flyers: 1000 units for $50-150
|
||||
|
||||
**Online (cheaper):**
|
||||
- Vistaprint
|
||||
- Overnight Prints
|
||||
- Sticker Mule
|
||||
|
||||
**Tip**: Get quotes from 3 different places!
|
||||
|
||||
---
|
||||
|
||||
## Common Mistakes Agents Should Avoid
|
||||
|
||||
### ❌ **Mistake 1: QR Code Too Small**
|
||||
|
||||
**Problem**: On street signs viewed from a distance, a small QR won't work
|
||||
|
||||
**Solution**: Minimum 6"x6" for outdoor signs
|
||||
|
||||
### ❌ **Mistake 2: Colors with Low Contrast**
|
||||
|
||||
**Problem**: Yellow QR on white background won't scan
|
||||
|
||||
**Solution**: Always use dark colors on light backgrounds (or vice versa)
|
||||
|
||||
### ❌ **Mistake 3: Not Testing Before Printing**
|
||||
|
||||
**Problem**: Print 1000 flyers and discover the QR doesn't work
|
||||
|
||||
**Solution**: Always test with a pilot print
|
||||
|
||||
### ❌ **Mistake 4: Broken or Temporary URL**
|
||||
|
||||
**Problem**: Property link expires, QR becomes useless
|
||||
|
||||
**Solution**: Use permanent URLs or editable dynamic QR
|
||||
|
||||
### ❌ **Mistake 5: No Usage Instructions**
|
||||
|
||||
**Problem**: Older person doesn't know what to do with the QR
|
||||
|
||||
**Solution**: Add "Point your phone camera here"
|
||||
|
||||
### ❌ **Mistake 6: Single QR Code for All Properties**
|
||||
|
||||
**Problem**: Don't know which property generated the lead
|
||||
|
||||
**Solution**: Create a specific QR for each property
|
||||
|
||||
### ❌ **Mistake 7: Low Quality Materials**
|
||||
|
||||
**Problem**: Label fades in 1 month in the sun
|
||||
|
||||
**Solution**: Invest in UV-resistant materials
|
||||
|
||||
---
|
||||
|
||||
## Success Stories
|
||||
|
||||
### **Case 1: Agent in New York**
|
||||
|
||||
**Strategy**: Placed QR Code on all 15 property signs
|
||||
|
||||
**Results:**
|
||||
- 127 scans in the first month
|
||||
- 34 WhatsApp conversations
|
||||
- 8 visits scheduled
|
||||
- 2 sales closed
|
||||
|
||||
**ROI**: Invested $150 in labels, earned $28,000 in commissions
|
||||
|
||||
### **Case 2: Real Estate Agency**
|
||||
|
||||
**Strategy**: Flyers with QR for virtual tour of new development
|
||||
|
||||
**Results:**
|
||||
- 5,000 flyers distributed
|
||||
- 890 virtual tour accesses
|
||||
- 156 registered interested buyers
|
||||
- 23 apartments sold in pre-sale
|
||||
|
||||
### **Case 3: Independent Agent**
|
||||
|
||||
**Strategy**: Adhesive labels at partner businesses
|
||||
|
||||
**Results:**
|
||||
- 200 labels distributed at 40 locations
|
||||
- 67 new contacts in 3 months
|
||||
- 12 property valuations scheduled
|
||||
- 3 exclusive listings captured
|
||||
|
||||
---
|
||||
|
||||
## Complementary Tools
|
||||
|
||||
### **Digital Content Creation**
|
||||
|
||||
- **Canva**: Create label and flyer layouts
|
||||
- **Matterport**: 360° virtual tours
|
||||
- **YouTube**: Host property videos
|
||||
- **Google Drive**: Property spec sheet PDFs
|
||||
|
||||
### **Lead Management**
|
||||
|
||||
- **Bitly**: Shorten URLs and track clicks
|
||||
- **Google Analytics**: Monitor traffic
|
||||
- **WhatsApp Business**: Organize conversations
|
||||
- **CRM tools**: Real estate CRM solutions
|
||||
|
||||
### **Online Printing**
|
||||
|
||||
- **Vistaprint**: Labels and flyers
|
||||
- **Overnight Prints**: Signs and banners
|
||||
- **Sticker Mule**: Premium stickers
|
||||
|
||||
---
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
### **Do I need to pay to create a QR Code?**
|
||||
|
||||
No! At QR Rapido you create unlimited QR Codes for free. You only pay if you want premium features like advanced tracking.
|
||||
|
||||
### **Does the QR Code work forever?**
|
||||
|
||||
Static QR Codes (free) work forever, but cannot be edited. Dynamic QR Codes (paid) can be edited even after printing.
|
||||
|
||||
### **Which QR type to use on property signs?**
|
||||
|
||||
I recommend **WhatsApp** with a pre-written message. That way the client already starts the conversation knowing which property they're asking about.
|
||||
|
||||
### **Can I put the agency logo on the QR?**
|
||||
|
||||
Yes, but carefully! Logos that are too large can make it harder to read. Keep the logo small (maximum 20% of the QR).
|
||||
|
||||
### **How many people scan QR Codes on signs?**
|
||||
|
||||
According to research, between 5-15% of people who see the sign scan the QR. In busy areas, this can generate dozens of leads per month.
|
||||
|
||||
### **Does the QR Code work at night?**
|
||||
|
||||
Yes, as long as there is some lighting. For best results, illuminate the sign.
|
||||
|
||||
### **Can I use the same QR on multiple materials?**
|
||||
|
||||
You can, but it's not recommended. Create different QR Codes to know where each lead came from (sign, flyer, label, etc.).
|
||||
|
||||
### **How do I know if the QR is working?**
|
||||
|
||||
Test immediately after creating! Use your own phone camera and at least 2 other people's phones to make sure.
|
||||
|
||||
---
|
||||
|
||||
## Professional Agent Checklist
|
||||
|
||||
Before printing, verify:
|
||||
|
||||
- [ ] QR Code tested on at least 3 different phones
|
||||
- [ ] Appropriate size for scanning distance
|
||||
- [ ] High contrast between QR and background
|
||||
- [ ] Clear call to action ("Scan here")
|
||||
- [ ] Visible contact information (name, license, phone)
|
||||
- [ ] Short URL if using a link (easier to scan)
|
||||
- [ ] Durable printing material (especially for outdoor use)
|
||||
- [ ] Safety margin around the QR (minimum 0.4")
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
QR Codes are the **cheapest and most effective tool** for modern agents to capture qualified leads. With an investment of less than $100 in labels and flyers, you can:
|
||||
|
||||
✅ Capture leads 24 hours a day
|
||||
✅ Facilitate instant contact via WhatsApp
|
||||
✅ Show impressive virtual tours
|
||||
✅ Track which materials generate the most results
|
||||
✅ Stand out from the conservative competition
|
||||
|
||||
**The real estate market is increasingly digital. Those who don't adapt get left behind.**
|
||||
|
||||
---
|
||||
|
||||
## Get Started Now!
|
||||
|
||||
**Create your first real estate agent QR Code for free:**
|
||||
|
||||
1. [Generate WhatsApp QR Code](/) - For property signs
|
||||
2. [Generate vCard QR Code](/) - For business cards
|
||||
3. [Generate URL QR Code](/) - For virtual tours
|
||||
|
||||
**Turn your signs and flyers into lead generation machines!** 🏠📱🚀
|
||||
|
||||
---
|
||||
|
||||
## Bonus Materials
|
||||
|
||||
- 📋 Pre-written WhatsApp message template
|
||||
- 🎨 Editable label templates
|
||||
- 📊 QR Code tracking spreadsheet by property
|
||||
- 🎯 Professional printing checklist
|
||||
|
||||
**Want to stand out in the real estate market? Use QR Codes strategically and watch your results multiply!**
|
||||
@ -18,6 +18,7 @@ namespace QRRapidoApp.Controllers
|
||||
[Route("Developer/docs")]
|
||||
[Route("es-PY/Developer/docs")]
|
||||
[Route("es/Developer/docs")]
|
||||
[Route("en/Developer/docs")]
|
||||
public async Task<IActionResult> Index()
|
||||
{
|
||||
var culture = GetCulture();
|
||||
@ -29,6 +30,7 @@ namespace QRRapidoApp.Controllers
|
||||
[Route("Developer/docs/{slug}")]
|
||||
[Route("es-PY/Developer/docs/{slug}")]
|
||||
[Route("es/Developer/docs/{slug}")]
|
||||
[Route("en/Developer/docs/{slug}")]
|
||||
public async Task<IActionResult> Article(string slug)
|
||||
{
|
||||
var culture = GetCulture();
|
||||
@ -57,6 +59,8 @@ namespace QRRapidoApp.Controllers
|
||||
if (path.StartsWith("/es-PY", StringComparison.OrdinalIgnoreCase)) return "es-PY";
|
||||
if (path.StartsWith("/es/", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(path, "/es", StringComparison.OrdinalIgnoreCase)) return "es";
|
||||
if (path.StartsWith("/en/", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(path, "/en", StringComparison.OrdinalIgnoreCase)) return "en";
|
||||
return "pt-BR";
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,10 @@ using System.Security.Claims;
|
||||
namespace QRRapidoApp.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Route("Developer")]
|
||||
[Route("es-PY/Developer")]
|
||||
[Route("es/Developer")]
|
||||
[Route("en/Developer")]
|
||||
public class DeveloperController : Controller
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
@ -23,7 +27,7 @@ namespace QRRapidoApp.Controllers
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("")]
|
||||
public async Task<IActionResult> Index()
|
||||
{
|
||||
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
@ -36,7 +40,7 @@ namespace QRRapidoApp.Controllers
|
||||
return View(user);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("GenerateKey")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> GenerateKey(string keyName)
|
||||
{
|
||||
@ -46,7 +50,7 @@ namespace QRRapidoApp.Controllers
|
||||
if (string.IsNullOrWhiteSpace(keyName) || keyName.Length > 50)
|
||||
{
|
||||
TempData["Error"] = "Nome da chave inválido (máx. 50 caracteres).";
|
||||
return RedirectToAction(nameof(Index));
|
||||
return Redirect(GetDevUrl());
|
||||
}
|
||||
|
||||
var user = await _userService.GetUserAsync(userId);
|
||||
@ -55,7 +59,7 @@ namespace QRRapidoApp.Controllers
|
||||
if (user.ApiKeys.Count(k => k.IsActive) >= 5)
|
||||
{
|
||||
TempData["Error"] = "Limite de 5 chaves ativas atingido. Revogue uma antes de criar outra.";
|
||||
return RedirectToAction(nameof(Index));
|
||||
return Redirect(GetDevUrl());
|
||||
}
|
||||
|
||||
var (rawKey, prefix) = await _userService.GenerateApiKeyAsync(userId, keyName.Trim());
|
||||
@ -67,7 +71,7 @@ namespace QRRapidoApp.Controllers
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("Pricing")]
|
||||
public async Task<IActionResult> Pricing()
|
||||
{
|
||||
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
@ -80,7 +84,7 @@ namespace QRRapidoApp.Controllers
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("SubscribeApi")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> SubscribeApi(string planTier)
|
||||
{
|
||||
@ -92,7 +96,7 @@ namespace QRRapidoApp.Controllers
|
||||
tier == ApiPlanTier.Enterprise)
|
||||
{
|
||||
TempData["Error"] = "Plano inválido selecionado.";
|
||||
return RedirectToAction(nameof(Pricing));
|
||||
return Redirect(GetDevUrl("Pricing"));
|
||||
}
|
||||
|
||||
try
|
||||
@ -105,11 +109,11 @@ namespace QRRapidoApp.Controllers
|
||||
{
|
||||
_logger.LogError(ex, "Error creating API subscription checkout for user {UserId}", userId);
|
||||
TempData["Error"] = "Erro ao criar sessão de pagamento. Tente novamente.";
|
||||
return RedirectToAction(nameof(Pricing));
|
||||
return Redirect(GetDevUrl("Pricing"));
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("RevokeKey")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> RevokeKey(string prefix)
|
||||
{
|
||||
@ -119,7 +123,7 @@ namespace QRRapidoApp.Controllers
|
||||
if (string.IsNullOrWhiteSpace(prefix))
|
||||
{
|
||||
TempData["Error"] = "Chave inválida.";
|
||||
return RedirectToAction(nameof(Index));
|
||||
return Redirect(GetDevUrl());
|
||||
}
|
||||
|
||||
var revoked = await _userService.RevokeApiKeyAsync(userId, prefix);
|
||||
@ -142,7 +146,20 @@ namespace QRRapidoApp.Controllers
|
||||
if (path.StartsWith("/es-PY", StringComparison.OrdinalIgnoreCase)) return "es-PY";
|
||||
if (path.StartsWith("/es/", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(path, "/es", StringComparison.OrdinalIgnoreCase)) return "es";
|
||||
if (path.StartsWith("/en/", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(path, "/en", StringComparison.OrdinalIgnoreCase)) return "en";
|
||||
return "pt-BR";
|
||||
}
|
||||
|
||||
private string GetDevUrl(string action = "")
|
||||
{
|
||||
var base_ = GetCulture() switch {
|
||||
"es-PY" => "/es-PY/Developer",
|
||||
"es" => "/es/Developer",
|
||||
"en" => "/en/Developer",
|
||||
_ => "/Developer"
|
||||
};
|
||||
return string.IsNullOrEmpty(action) ? base_ : $"{base_}/{action}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@ namespace QRRapidoApp.Controllers
|
||||
[HttpGet]
|
||||
[Route("/")]
|
||||
[Route("es-PY")]
|
||||
[Route("en")]
|
||||
public async Task<IActionResult> Index(string? qrType = null)
|
||||
{
|
||||
var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
@ -116,36 +117,44 @@ namespace QRRapidoApp.Controllers
|
||||
|
||||
[Route("pix")]
|
||||
[Route("es-PY/pix")]
|
||||
[Route("en/pix")]
|
||||
public async Task<IActionResult> Pix() => await Index("pix");
|
||||
|
||||
[Route("wifi")]
|
||||
[Route("es-PY/wifi")]
|
||||
[Route("en/wifi")]
|
||||
public async Task<IActionResult> Wifi() => await Index("wifi");
|
||||
|
||||
[Route("vcard")]
|
||||
[Route("es-PY/vcard")]
|
||||
[Route("en/vcard")]
|
||||
public async Task<IActionResult> VCard() => await Index("vcard");
|
||||
|
||||
[Route("whatsapp")]
|
||||
[Route("es-PY/whatsapp")]
|
||||
[Route("en/whatsapp")]
|
||||
public async Task<IActionResult> WhatsApp() => await Index("whatsapp");
|
||||
|
||||
[Route("email")]
|
||||
[Route("es-PY/email")]
|
||||
[Route("en/email")]
|
||||
public async Task<IActionResult> Email() => await Index("email");
|
||||
|
||||
[Route("sms")]
|
||||
[Route("es-PY/sms")]
|
||||
[Route("en/sms")]
|
||||
public async Task<IActionResult> Sms() => await Index("sms");
|
||||
|
||||
[Route("texto")]
|
||||
[Route("text")]
|
||||
[Route("es-PY/texto")]
|
||||
[Route("es-PY/text")]
|
||||
[Route("en/text")]
|
||||
public async Task<IActionResult> Text() => await Index("text");
|
||||
|
||||
[Route("url")]
|
||||
[Route("es-PY/url")]
|
||||
[Route("en/url")]
|
||||
public async Task<IActionResult> UrlType() => await Index("url");
|
||||
|
||||
public IActionResult Privacy()
|
||||
|
||||
@ -29,9 +29,11 @@ namespace QRRapidoApp.Controllers
|
||||
|
||||
// Portuguese: /tutoriais/{slug} (canonical, no prefix)
|
||||
// Spanish: /es-PY/tutoriais/{slug}
|
||||
// English: /en/tutoriais/{slug}
|
||||
[Route("tutoriais/{slug}")]
|
||||
[Route("es-PY/tutoriais/{slug}")]
|
||||
[Route("es/tutoriais/{slug}")]
|
||||
[Route("en/tutoriais/{slug}")]
|
||||
public async Task<IActionResult> Article(string slug, string? culture = null)
|
||||
{
|
||||
try
|
||||
@ -40,6 +42,7 @@ namespace QRRapidoApp.Controllers
|
||||
var reqPath = Request.Path.Value ?? "";
|
||||
culture ??= reqPath.StartsWith("/es-PY", StringComparison.OrdinalIgnoreCase) ? "es-PY"
|
||||
: reqPath.StartsWith("/es/", StringComparison.OrdinalIgnoreCase) ? "es"
|
||||
: reqPath.StartsWith("/en/", StringComparison.OrdinalIgnoreCase) ? "en"
|
||||
: "pt-BR";
|
||||
|
||||
var article = await _markdownService.GetArticleAsync(slug, culture);
|
||||
@ -89,9 +92,11 @@ namespace QRRapidoApp.Controllers
|
||||
|
||||
// Portuguese: /tutoriais (canonical, no prefix)
|
||||
// Spanish: /es-PY/tutoriais
|
||||
// English: /en/tutoriais
|
||||
[Route("tutoriais")]
|
||||
[Route("es-PY/tutoriais")]
|
||||
[Route("es/tutoriais")]
|
||||
[Route("en/tutoriais")]
|
||||
public async Task<IActionResult> Index(string? culture = null)
|
||||
{
|
||||
try
|
||||
@ -100,6 +105,7 @@ namespace QRRapidoApp.Controllers
|
||||
var reqPath = Request.Path.Value ?? "";
|
||||
culture ??= reqPath.StartsWith("/es-PY", StringComparison.OrdinalIgnoreCase) ? "es-PY"
|
||||
: reqPath.StartsWith("/es/", StringComparison.OrdinalIgnoreCase) ? "es"
|
||||
: reqPath.StartsWith("/en/", StringComparison.OrdinalIgnoreCase) ? "en"
|
||||
: "pt-BR";
|
||||
|
||||
var articles = await _markdownService.GetAllArticlesAsync(culture);
|
||||
@ -112,9 +118,13 @@ namespace QRRapidoApp.Controllers
|
||||
ViewBag.UserName = User.Identity?.Name ?? "";
|
||||
_adDisplayService.SetViewBagAds(ViewBag);
|
||||
|
||||
ViewBag.Title = culture == "pt-BR" ? "Tutoriais QR Code" : "Tutoriales Código QR";
|
||||
ViewBag.Title = culture == "pt-BR" ? "Tutoriais QR Code"
|
||||
: culture == "en" ? "QR Code Tutorials"
|
||||
: "Tutoriales Código QR";
|
||||
ViewBag.Description = culture == "pt-BR"
|
||||
? "Aprenda a criar e usar QR Codes com nossos tutoriais completos"
|
||||
: culture == "en"
|
||||
? "Learn how to create and use QR Codes with our complete step-by-step tutorials"
|
||||
: "Aprende a crear y usar códigos QR con nuestros tutoriales completos";
|
||||
ViewBag.Culture = culture;
|
||||
|
||||
|
||||
@ -16,6 +16,16 @@ namespace QRRapidoApp.Filters
|
||||
|
||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||
{
|
||||
// [AllowAnonymous] on the action bypasses this filter
|
||||
var hasAllowAnonymous = context.ActionDescriptor.EndpointMetadata
|
||||
.OfType<Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute>()
|
||||
.Any();
|
||||
if (hasAllowAnonymous)
|
||||
{
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
|
||||
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<ApiKeyAuthorizeAttribute>>();
|
||||
|
||||
try
|
||||
|
||||
@ -10,13 +10,14 @@ namespace QRRapidoApp.Middleware
|
||||
/// - "/" → Retorna 200 OK em Português (canonical)
|
||||
/// - "/pt-BR" ou "/pt-BR/*" → Redireciona 301 para "/" ou "/*" (sem prefixo)
|
||||
/// - "/es-PY" ou "/es-PY/*" → Retorna 200 OK em Espanhol (mantém URL)
|
||||
/// - "/en" ou "/en/*" → Retorna 200 OK em Inglês (mantém URL)
|
||||
/// - "/pix", "/wifi", etc. → Retorna 200 OK em Português (sem redirect)
|
||||
/// </summary>
|
||||
public class LanguageRedirectionMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ILogger<LanguageRedirectionMiddleware> _logger;
|
||||
private readonly string[] _supportedCultures = { "pt-BR", "es-PY", "es" };
|
||||
private readonly string[] _supportedCultures = { "pt-BR", "es-PY", "es", "en" };
|
||||
private const string DefaultCulture = "pt-BR";
|
||||
private const string CookieName = ".AspNetCore.Culture";
|
||||
|
||||
@ -84,7 +85,15 @@ namespace QRRapidoApp.Middleware
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle aliases or unsupported cultures (e.g. /en/, /pt/)
|
||||
// Supported: en (English)
|
||||
if (string.Equals(firstSegment, "en", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
SetCulture(context, "en");
|
||||
await _next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle aliases or unsupported cultures (e.g. /en-US/, /pt/)
|
||||
if (TryHandleCultureAliasOrUnknown(context, firstSegment, segments))
|
||||
{
|
||||
return;
|
||||
@ -108,13 +117,14 @@ namespace QRRapidoApp.Middleware
|
||||
{
|
||||
// Map known aliases to canonical forms
|
||||
if (string.Equals(firstSegment, "es-py", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return RedirectToLanguage(context, "es-PY", segments);
|
||||
}
|
||||
|
||||
// For anything else that looks like a culture (en, pt, fr, etc.)
|
||||
// but isn't explicitly es-PY, we redirect to the canonical (no prefix)
|
||||
// This prevents 404s for /en/, /pt-BR/ (redirects to /), etc.
|
||||
if (string.Equals(firstSegment, "en-us", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(firstSegment, "en-gb", StringComparison.OrdinalIgnoreCase))
|
||||
return RedirectToLanguage(context, "en", segments);
|
||||
|
||||
// For anything else that looks like a culture (pt, fr, de, etc.)
|
||||
// redirect to the canonical Portuguese URL (no prefix).
|
||||
return RedirectToCanonical(context, segments);
|
||||
}
|
||||
|
||||
|
||||
@ -226,6 +226,7 @@ builder.Services.Configure<RequestLocalizationOptions>(options =>
|
||||
new CultureInfo("pt-BR"),
|
||||
new CultureInfo("es-PY"),
|
||||
new CultureInfo("es"),
|
||||
new CultureInfo("en"),
|
||||
};
|
||||
|
||||
options.DefaultRequestCulture = new RequestCulture("pt-BR", "pt-BR");
|
||||
@ -463,7 +464,7 @@ app.MapHealthChecks("/healthcheck");
|
||||
// Language routes (must be first for WEB)
|
||||
app.MapControllerRoute(
|
||||
name: "localized",
|
||||
pattern: "{culture:regex(^(pt-BR|es-PY|es)$)}/{controller=Home}/{action=Index}/{id?}");
|
||||
pattern: "{culture:regex(^(pt-BR|es-PY|es|en)$)}/{controller=Home}/{action=Index}/{id?}");
|
||||
|
||||
app.MapControllerRoute(
|
||||
name: "api_v1",
|
||||
|
||||
@ -9,7 +9,7 @@ namespace QRRapidoApp.Providers
|
||||
// First check if the middleware has already determined the culture (e.g. for static routes like /es-PY/pix)
|
||||
if (httpContext.Items.TryGetValue("Culture", out var cultureItem) && cultureItem is string cultureFromMiddleware)
|
||||
{
|
||||
var supportedCultures = new[] { "pt-BR", "es-PY" };
|
||||
var supportedCultures = new[] { "pt-BR", "es-PY", "en" };
|
||||
if (supportedCultures.Contains(cultureFromMiddleware))
|
||||
{
|
||||
return Task.FromResult<ProviderCultureResult?>(new ProviderCultureResult(cultureFromMiddleware, cultureFromMiddleware));
|
||||
@ -24,7 +24,7 @@ namespace QRRapidoApp.Providers
|
||||
if (!string.IsNullOrEmpty(culture))
|
||||
{
|
||||
// Map the supported cultures
|
||||
var supportedCultures = new[] { "pt-BR", "es-PY" };
|
||||
var supportedCultures = new[] { "pt-BR", "es-PY", "en" };
|
||||
if (supportedCultures.Contains(culture))
|
||||
{
|
||||
return Task.FromResult<ProviderCultureResult?>(new ProviderCultureResult(culture, culture));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -2104,7 +2104,7 @@
|
||||
</data>
|
||||
<!-- Tutorial Section -->
|
||||
<data name="ViewTutorials" xml:space="preserve">
|
||||
<value>Ver Tutoriales</value>
|
||||
<value>Tutoriales QR</value>
|
||||
</data>
|
||||
<data name="LearnMore" xml:space="preserve">
|
||||
<value>Aprende Más</value>
|
||||
@ -2113,7 +2113,7 @@
|
||||
<value>Guías completas sobre códigos QR</value>
|
||||
</data>
|
||||
<data name="ViewAllTutorials" xml:space="preserve">
|
||||
<value>Ver Todos los Tutoriales</value>
|
||||
<value>Tutoriales QR</value>
|
||||
</data>
|
||||
<data name="RealEstateAndBrokers" xml:space="preserve">
|
||||
<value>Inmobiliaria y Corredores</value>
|
||||
|
||||
@ -2257,7 +2257,7 @@
|
||||
</data>
|
||||
<!-- Tutorial Section -->
|
||||
<data name="ViewTutorials" xml:space="preserve">
|
||||
<value>Ver Tutoriais</value>
|
||||
<value>Tutoriais QR</value>
|
||||
</data>
|
||||
<data name="LearnMore" xml:space="preserve">
|
||||
<value>Aprenda Mais</value>
|
||||
@ -2266,7 +2266,7 @@
|
||||
<value>Guias completos sobre QR Codes</value>
|
||||
</data>
|
||||
<data name="ViewAllTutorials" xml:space="preserve">
|
||||
<value>Ver Todos os Tutoriais</value>
|
||||
<value>Tutoriais QR</value>
|
||||
</data>
|
||||
<data name="RealEstateAndBrokers" xml:space="preserve">
|
||||
<value>Imóveis e Corretores</value>
|
||||
|
||||
@ -3,19 +3,19 @@
|
||||
ViewData["Title"] = Model.Metadata.Title + " — QRRapido Docs";
|
||||
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||
|
||||
var culture = ViewBag.Culture as string ?? "pt-BR";
|
||||
var isEs = culture == "es-PY";
|
||||
var devBase = isEs ? "/es-PY/Developer" : "/Developer";
|
||||
var slug = ViewBag.Slug as string;
|
||||
var isEn = (ViewBag.Culture as string) == "en";
|
||||
var isEs = (ViewBag.Culture as string) == "es-PY" || (ViewBag.Culture as string) == "es";
|
||||
var devBase = isEn ? "/en/Developer" : isEs ? "/es-PY/Developer" : "/Developer";
|
||||
var slug = ViewBag.Slug as string;
|
||||
|
||||
string T(string pt, string es) => isEs ? es : pt;
|
||||
string T(string pt, string es, string en) => isEn ? en : isEs ? es : pt;
|
||||
}
|
||||
|
||||
<div class="container mt-4 mb-5">
|
||||
|
||||
<nav aria-label="breadcrumb" class="mb-4">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="@devBase">@T("Portal do Desenvolvedor", "Portal del Desarrollador")</a></li>
|
||||
<li class="breadcrumb-item"><a href="@devBase">@T("Portal do Desenvolvedor", "Portal del Desarrollador", "Developer Portal")</a></li>
|
||||
<li class="breadcrumb-item"><a href="@devBase/docs">Docs</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">@Model.Metadata.Title</li>
|
||||
</ol>
|
||||
@ -27,7 +27,7 @@
|
||||
<header class="mb-4">
|
||||
<h1 class="mb-3">@Model.Metadata.Title</h1>
|
||||
<p class="text-muted small">
|
||||
<i class="fas fa-clock me-1"></i> @Model.Metadata.ReadingTimeMinutes @T("min de leitura", "min de lectura")
|
||||
<i class="fas fa-clock me-1"></i> @Model.Metadata.ReadingTimeMinutes @T("min de leitura", "min de lectura", "min read")
|
||||
·
|
||||
<i class="fas fa-calendar me-1"></i> @Model.Metadata.Date.ToString("dd/MM/yyyy")
|
||||
</p>
|
||||
@ -40,7 +40,7 @@
|
||||
</div>
|
||||
|
||||
<footer class="mt-5 pt-3 border-top">
|
||||
<small class="text-muted">@T("Última atualização:", "Última actualización:") @Model.Metadata.LastMod.ToString("dd/MM/yyyy")</small>
|
||||
<small class="text-muted">@T("Última atualização:", "Última actualización:", "Last updated:") @Model.Metadata.LastMod.ToString("dd/MM/yyyy")</small>
|
||||
</footer>
|
||||
</article>
|
||||
|
||||
@ -48,20 +48,20 @@
|
||||
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-header bg-primary text-white py-2">
|
||||
<h6 class="mb-0"><i class="fas fa-rocket me-2"></i>@T("Links Rápidos", "Links Pya'e")</h6>
|
||||
<h6 class="mb-0"><i class="fas fa-rocket me-2"></i>@T("Links Rápidos", "Links Pya'e", "Quick Links")</h6>
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
<a href="@devBase" class="list-group-item list-group-item-action small">
|
||||
<i class="fas fa-key me-2 text-primary"></i>@T("Minhas Chaves de API", "Mis Claves de API")
|
||||
<i class="fas fa-key me-2 text-primary"></i>@T("Minhas Chaves de API", "Mis Claves de API", "My API Keys")
|
||||
</a>
|
||||
<a href="/api/docs" target="_blank" class="list-group-item list-group-item-action small">
|
||||
<i class="fas fa-code me-2 text-success"></i>Swagger / OpenAPI
|
||||
</a>
|
||||
<a href="@devBase/Pricing" class="list-group-item list-group-item-action small">
|
||||
<i class="fas fa-arrow-up me-2 text-warning"></i>@T("Planos de API", "Planes de API")
|
||||
<i class="fas fa-arrow-up me-2 text-warning"></i>@T("Planos de API", "Planes de API", "API Plans")
|
||||
</a>
|
||||
<a href="@devBase/docs" class="list-group-item list-group-item-action small">
|
||||
<i class="fas fa-book me-2 text-info"></i>@T("Todos os Tutoriais", "Todos los Tutoriales")
|
||||
<i class="fas fa-book me-2 text-info"></i>@T("Todos os Tutoriais", "Todos los Tutoriales", "All Tutorials")
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -70,7 +70,7 @@
|
||||
{
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-header bg-white py-2">
|
||||
<h6 class="mb-0"><i class="fas fa-bookmark me-2 text-secondary"></i>@T("Outros Tutoriais", "Otros Tutoriales")</h6>
|
||||
<h6 class="mb-0"><i class="fas fa-bookmark me-2 text-secondary"></i>@T("Outros Tutoriais", "Otros Tutoriales", "Other Tutorials")</h6>
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
@foreach (var related in Model.RelatedArticles)
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
ViewData["Title"] = "Docs & Tutoriais para Desenvolvedores";
|
||||
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||
|
||||
var culture = ViewBag.Culture as string ?? "pt-BR";
|
||||
var isEs = culture == "es-PY";
|
||||
var devBase = isEs ? "/es-PY/Developer" : "/Developer";
|
||||
var isEn = (ViewBag.Culture as string) == "en";
|
||||
var isEs = (ViewBag.Culture as string) == "es-PY" || (ViewBag.Culture as string) == "es";
|
||||
var devBase = isEn ? "/en/Developer" : isEs ? "/es-PY/Developer" : "/Developer";
|
||||
|
||||
string T(string pt, string es) => isEs ? es : pt;
|
||||
string T(string pt, string es, string en) => isEn ? en : isEs ? es : pt;
|
||||
}
|
||||
|
||||
<div class="container mt-4 mb-5">
|
||||
@ -16,13 +16,13 @@
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="me-3"><i class="fas fa-book-open fa-2x text-primary"></i></div>
|
||||
<div>
|
||||
<h1 class="h3 mb-0">@T("Docs & Tutoriais", "Docs & Tutoriales")</h1>
|
||||
<p class="text-muted mb-0 small">@T("Guias técnicos para integrar e usar a API QRRapido.", "Guías técnicas para integrar ha usar la API QRRapido.")</p>
|
||||
<h1 class="h3 mb-0">@T("Docs & Tutoriais", "Docs & Tutoriales", "Docs & Tutorials")</h1>
|
||||
<p class="text-muted mb-0 small">@T("Guias técnicos para integrar e usar a API QRRapido.", "Guías técnicas para integrar ha usar la API QRRapido.", "Technical guides to integrate and use the QRRapido API.")</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="@devBase" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="fas fa-key me-1"></i> @T("Minhas Chaves", "Mis Claves")
|
||||
<i class="fas fa-key me-1"></i> @T("Minhas Chaves", "Mis Claves", "My Keys")
|
||||
</a>
|
||||
<a href="/api/docs" target="_blank" class="btn btn-outline-success btn-sm">
|
||||
<i class="fas fa-code me-1"></i> Swagger
|
||||
@ -42,11 +42,11 @@
|
||||
<p class="card-text text-muted flex-grow-1 small">@article.Description</p>
|
||||
<div class="mb-3">
|
||||
<small class="text-muted">
|
||||
<i class="fas fa-clock me-1"></i> @article.ReadingTimeMinutes @T("min de leitura", "min de lectura")
|
||||
<i class="fas fa-clock me-1"></i> @article.ReadingTimeMinutes @T("min de leitura", "min de lectura", "min read")
|
||||
</small>
|
||||
</div>
|
||||
<a href="@devBase/docs/@article.Slug" class="btn btn-primary btn-sm">
|
||||
@T("Ler", "Leer") <i class="fas fa-arrow-right ms-1"></i>
|
||||
@T("Ler", "Leer", "Read") <i class="fas fa-arrow-right ms-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -58,7 +58,7 @@
|
||||
{
|
||||
<div class="text-center py-5">
|
||||
<i class="fas fa-book fa-3x text-muted opacity-25 mb-3"></i>
|
||||
<p class="text-muted">@T("Nenhum artigo encontrado.", "Ningún artículo encontrado.")</p>
|
||||
<p class="text-muted">@T("Nenhum artigo encontrado.", "Ningún artículo encontrado.", "No articles found.")</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -12,11 +12,11 @@
|
||||
var revokedKeys = Model.ApiKeys.Where(k => !k.IsActive).OrderByDescending(k => k.CreatedAt).ToList();
|
||||
|
||||
var baseUrl = Context.Request.Scheme + "://" + Context.Request.Host;
|
||||
var culture = ViewBag.Culture as string ?? "pt-BR";
|
||||
var isEs = culture == "es-PY";
|
||||
var docsBase = isEs ? "/es-PY/Developer" : "/Developer";
|
||||
var isEn = (ViewBag.Culture as string) == "en";
|
||||
var isEs = (ViewBag.Culture as string) == "es-PY" || (ViewBag.Culture as string) == "es";
|
||||
var docsBase = isEn ? "/en/Developer" : isEs ? "/es-PY/Developer" : "/Developer";
|
||||
|
||||
string T(string pt, string es) => isEs ? es : pt;
|
||||
string T(string pt, string es, string en = null) => isEn && en != null ? en : isEs ? es : pt;
|
||||
}
|
||||
|
||||
<div class="container mt-4 mb-5">
|
||||
@ -28,29 +28,30 @@
|
||||
<i class="fas fa-code fa-2x text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="h3 mb-0">@T("Portal do Desenvolvedor", "Portal del Desarrollador")</h1>
|
||||
<h1 class="h3 mb-0">@T("Portal do Desenvolvedor", "Portal del Desarrollador", "Developer Portal")</h1>
|
||||
<p class="text-muted mb-0 small">
|
||||
@T("Gerencie suas chaves de API e integre o QR Rapido nas suas aplicações.",
|
||||
"Gestioná tus claves de API ha integrá QR Rapido en tus aplicaciones.")
|
||||
"Gestioná tus claves de API ha integrá QR Rapido en tus aplicaciones.",
|
||||
"Manage your API keys and integrate QR Rapido into your applications.")
|
||||
@{
|
||||
var tier = Model.ApiSubscription?.EffectiveTier ?? QRRapidoApp.Models.ApiPlanTier.Free;
|
||||
var tierLabel = tier == QRRapidoApp.Models.ApiPlanTier.Free
|
||||
? "<span class='badge bg-secondary ms-2'>Free</span>"
|
||||
: $"<span class='badge bg-primary ms-2'>{tier}</span>";
|
||||
}
|
||||
@T("Plano atual:", "Plan actual:") @Html.Raw(tierLabel)
|
||||
@T("Plano atual:", "Plan actual:", "Current plan:") @Html.Raw(tierLabel)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="@docsBase/docs" class="btn btn-outline-info btn-sm">
|
||||
<i class="fas fa-book me-1"></i> @T("Tutoriais", "Tutoriales")
|
||||
<i class="fas fa-book me-1"></i> Docs API
|
||||
</a>
|
||||
<a href="/api/docs" target="_blank" class="btn btn-outline-success btn-sm">
|
||||
<i class="fas fa-code me-1"></i> Swagger
|
||||
</a>
|
||||
<a href="@docsBase/Pricing" class="btn btn-outline-primary btn-sm">
|
||||
<i class="fas fa-arrow-up me-1"></i> @T("Ver Planos de API", "Ver Planes de API")
|
||||
<i class="fas fa-arrow-up me-1"></i> @T("Ver Planos de API", "Ver Planes de API", "API Plans")
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -5,24 +5,25 @@
|
||||
|
||||
var currentTier = ViewBag.CurrentTier as ApiPlanTier? ?? ApiPlanTier.Free;
|
||||
var errorMsg = TempData["Error"] as string;
|
||||
var culture = ViewBag.Culture as string ?? "pt-BR";
|
||||
var isEs = culture == "es-PY";
|
||||
var devBase = isEs ? "/es-PY/Developer" : "/Developer";
|
||||
var isEn = (ViewBag.Culture as string) == "en";
|
||||
var isEs = (ViewBag.Culture as string) == "es-PY" || (ViewBag.Culture as string) == "es";
|
||||
var devBase = isEn ? "/en/Developer" : isEs ? "/es-PY/Developer" : "/Developer";
|
||||
|
||||
string T(string pt, string es) => isEs ? es : pt;
|
||||
string T(string pt, string es, string en = null) => isEn && en != null ? en : isEs ? es : pt;
|
||||
}
|
||||
|
||||
<div class="container mt-4 mb-5">
|
||||
|
||||
<div class="text-center mb-5">
|
||||
<h1 class="h2 fw-bold">@T("Planos de API", "Planes de API")</h1>
|
||||
<h1 class="h2 fw-bold">@T("Planos de API", "Planes de API", "API Plans")</h1>
|
||||
<p class="text-muted">
|
||||
@T("Escolha o plano que melhor se adapta à sua integração.",
|
||||
"Elegí el plan porã que mejor se adapte a tu integración.")
|
||||
"Elegí el plan porã que mejor se adapte a tu integración.",
|
||||
"Choose the plan that best fits your integration.")
|
||||
<br>
|
||||
@T("Todos os planos incluem a", "Todos los planes incluyen la")
|
||||
@T("Todos os planos incluem a", "Todos los planes incluyen la", "All plans include the")
|
||||
<strong>API REST</strong>
|
||||
@T("com autenticação por chave.", "con autenticación por clave.")
|
||||
@T("com autenticação por chave.", "con autenticación por clave.", "with key authentication.")
|
||||
</p>
|
||||
@if (!string.IsNullOrEmpty(errorMsg))
|
||||
{
|
||||
@ -174,7 +175,7 @@
|
||||
|
||||
<div class="text-center mt-3">
|
||||
<a href="@devBase" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left me-2"></i>@T("Voltar ao Portal", "Volver al Portal")
|
||||
<i class="fas fa-arrow-left me-2"></i>@T("Voltar ao Portal", "Volver al Portal", "Back to Portal")
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -18,33 +18,38 @@
|
||||
var appEnvironment = Configuration["App:Environment"] ?? HostEnvironment?.EnvironmentName ?? "Unknown";
|
||||
var secretsLoaded = Configuration.GetValue<bool>("App:SecretsLoaded");
|
||||
|
||||
// SEO: Determine if current page is Spanish (for URL building)
|
||||
// SEO: Determine current culture from URL
|
||||
var requestPath = Context.Request.Path.Value ?? "/";
|
||||
var isSpanish = requestPath.StartsWith("/es-PY", StringComparison.OrdinalIgnoreCase);
|
||||
var isSpanish = requestPath.StartsWith("/es-PY", StringComparison.OrdinalIgnoreCase)
|
||||
|| requestPath.StartsWith("/es/", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(requestPath, "/es", StringComparison.OrdinalIgnoreCase);
|
||||
var isEnglish = requestPath.StartsWith("/en/", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(requestPath, "/en", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// Get path without culture prefix for building alternate URLs
|
||||
var pathWithoutCulture = requestPath;
|
||||
if (isSpanish && requestPath.Length > 6)
|
||||
{
|
||||
pathWithoutCulture = requestPath.Substring(6); // Remove "/es-PY"
|
||||
}
|
||||
else if (isSpanish)
|
||||
{
|
||||
pathWithoutCulture = "/";
|
||||
}
|
||||
if (requestPath.StartsWith("/es-PY", StringComparison.OrdinalIgnoreCase))
|
||||
pathWithoutCulture = requestPath.Length > 6 ? requestPath.Substring(6) : "/";
|
||||
else if (requestPath.StartsWith("/es/", StringComparison.OrdinalIgnoreCase))
|
||||
pathWithoutCulture = requestPath.Length > 3 ? requestPath.Substring(3) : "/";
|
||||
else if (requestPath.StartsWith("/en/", StringComparison.OrdinalIgnoreCase))
|
||||
pathWithoutCulture = requestPath.Length > 3 ? requestPath.Substring(3) : "/";
|
||||
if (string.IsNullOrEmpty(pathWithoutCulture)) pathWithoutCulture = "/";
|
||||
|
||||
// Canonical URL - for Portuguese it's without prefix, for Spanish it's with /es-PY
|
||||
var canonicalUrl = isSpanish
|
||||
// Canonical URL
|
||||
var canonicalUrl = isEnglish
|
||||
? $"https://qrrapido.site/en{(pathWithoutCulture == "/" ? "" : pathWithoutCulture)}"
|
||||
: isSpanish
|
||||
? $"https://qrrapido.site/es-PY{(pathWithoutCulture == "/" ? "" : pathWithoutCulture)}"
|
||||
: $"https://qrrapido.site{pathWithoutCulture}";
|
||||
|
||||
// Alternate URLs for hreflang
|
||||
var ptUrl = $"https://qrrapido.site{pathWithoutCulture}";
|
||||
var esUrl = $"https://qrrapido.site/es-PY{(pathWithoutCulture == "/" ? "" : pathWithoutCulture)}";
|
||||
var enUrl = $"https://qrrapido.site/en{(pathWithoutCulture == "/" ? "" : pathWithoutCulture)}";
|
||||
|
||||
// Culture prefix for internal links
|
||||
var culturePrefix = isSpanish ? "/es-PY" : "";
|
||||
var culturePrefix = isEnglish ? "/en" : isSpanish ? "/es-PY" : "";
|
||||
|
||||
if (User?.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
@ -86,6 +91,7 @@
|
||||
<!-- Hreflang for multilingual SEO -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="@ptUrl">
|
||||
<link rel="alternate" hreflang="es-PY" href="@esUrl">
|
||||
<link rel="alternate" hreflang="en" href="@enUrl">
|
||||
<link rel="alternate" hreflang="x-default" href="@ptUrl">
|
||||
|
||||
<!-- Open Graph -->
|
||||
@ -319,7 +325,7 @@
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#" data-lang="pt-BR">🇧🇷 Português (Brasil)</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-lang="es-PY">🇵🇾 Español (Paraguay)</a></li>
|
||||
@* <li><a class="dropdown-item" href="#" data-lang="en">🇺🇸 English</a></li> *@
|
||||
<li><a class="dropdown-item" href="#" data-lang="en">🇺🇸 English</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
@{
|
||||
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||
ViewData["Title"] = Model.Metadata.Title;
|
||||
var isEn = (ViewBag.Culture as string) == "en";
|
||||
var isEs = (ViewBag.Culture as string) == "es-PY" || (ViewBag.Culture as string) == "es";
|
||||
string T(string pt, string es, string en) => isEn ? en : isEs ? es : pt;
|
||||
var baseUrl = "https://qrrapido.site";
|
||||
var articleUrl = $"{baseUrl}/{ViewBag.Culture}/tutoriais/{ViewBag.Slug}";
|
||||
}
|
||||
@ -84,7 +87,7 @@
|
||||
{
|
||||
"@@type": "ListItem",
|
||||
"position": 2,
|
||||
"name": "@(ViewBag.Culture == "pt-BR" ? "Tutoriais" : "Tutoriales")",
|
||||
"name": "@T("Tutoriais", "Tutoriales", "Tutorials")",
|
||||
"item": "@baseUrl/@ViewBag.Culture/tutoriais"
|
||||
},
|
||||
{
|
||||
@ -103,7 +106,7 @@
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/@ViewBag.Culture">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="/@ViewBag.Culture/tutoriais">@(ViewBag.Culture == "pt-BR" ? "Tutoriais" : "Tutoriales")</a></li>
|
||||
<li class="breadcrumb-item"><a href="/@ViewBag.Culture/tutoriais">@T("Tutoriais", "Tutoriales", "Tutorials")</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">@Model.Metadata.Title</li>
|
||||
</ol>
|
||||
</nav>
|
||||
@ -118,7 +121,7 @@
|
||||
<div class="text-muted mb-3">
|
||||
<span><i class="fas fa-user"></i> @Model.Metadata.Author</span> |
|
||||
<span><i class="fas fa-calendar"></i> @Model.Metadata.Date.ToString("dd MMM yyyy")</span> |
|
||||
<span><i class="fas fa-clock"></i> @Model.Metadata.ReadingTimeMinutes min @(ViewBag.Culture == "pt-BR" ? "de leitura" : "de lectura")</span>
|
||||
<span><i class="fas fa-clock"></i> @Model.Metadata.ReadingTimeMinutes min @T("de leitura", "de lectura", "read")</span>
|
||||
</div>
|
||||
|
||||
@if (!string.IsNullOrEmpty(Model.Metadata.Image))
|
||||
@ -138,7 +141,7 @@
|
||||
<footer class="mt-5 pt-4 border-top">
|
||||
<p class="text-muted">
|
||||
<small>
|
||||
@(ViewBag.Culture == "pt-BR" ? "Última atualização:" : "Última actualización:")
|
||||
@T("Última atualização:", "Última actualización:", "Last updated:")
|
||||
@Model.Metadata.LastMod.ToString("dd MMM yyyy HH:mm")
|
||||
</small>
|
||||
</p>
|
||||
@ -170,7 +173,7 @@
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="fas fa-book"></i>
|
||||
@(ViewBag.Culture == "pt-BR" ? "Artigos Relacionados" : "Artículos Relacionados")
|
||||
@T("Artigos Relacionados", "Artículos Relacionados", "Related Articles")
|
||||
</h5>
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
@ -193,15 +196,15 @@
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
<i class="fas fa-crown"></i>
|
||||
@(ViewBag.Culture == "pt-BR" ? "Seja Premium!" : "¡Hazte Premium!")
|
||||
@T("Seja Premium!", "¡Hazte Premium!", "Go Premium!")
|
||||
</h5>
|
||||
<p class="card-text">
|
||||
@(ViewBag.Culture == "pt-BR"
|
||||
? "QR codes ilimitados, sem anúncios e recursos avançados."
|
||||
: "Códigos QR ilimitados, sin anuncios y características avanzadas.")
|
||||
@T("QR codes ilimitados, sem anúncios e recursos avançados.",
|
||||
"Códigos QR ilimitados, sin anuncios y características avanzadas.",
|
||||
"Unlimited QR codes, no ads and advanced features.")
|
||||
</p>
|
||||
<a href="/@ViewBag.Culture/Pagamento/SelecaoPlano" class="btn btn-light btn-block">
|
||||
@(ViewBag.Culture == "pt-BR" ? "Conhecer Planos" : "Conocer Planes")
|
||||
@T("Conhecer Planos", "Conocer Planes", "View Plans")
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -212,21 +215,21 @@
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="fas fa-link"></i>
|
||||
@(ViewBag.Culture == "pt-BR" ? "Links Úteis" : "Enlaces Útiles")
|
||||
@T("Links Úteis", "Enlaces Útiles", "Useful Links")
|
||||
</h5>
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
<a href="/@ViewBag.Culture" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-qrcode"></i>
|
||||
@(ViewBag.Culture == "pt-BR" ? "Gerar QR Code" : "Generar Código QR")
|
||||
@T("Gerar QR Code", "Generar Código QR", "Generate QR Code")
|
||||
</a>
|
||||
<a href="/@ViewBag.Culture/FAQ" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-question-circle"></i>
|
||||
@(ViewBag.Culture == "pt-BR" ? "Perguntas Frequentes" : "Preguntas Frecuentes")
|
||||
@T("Perguntas Frequentes", "Preguntas Frecuentes", "FAQ")
|
||||
</a>
|
||||
<a href="/@ViewBag.Culture/Contact" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-envelope"></i>
|
||||
@(ViewBag.Culture == "pt-BR" ? "Contato" : "Contacto")
|
||||
@T("Contato", "Contacto", "Contact")
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
@model List<QRRapidoApp.Models.ArticleMetadata>
|
||||
@{
|
||||
ViewData["Title"] = ViewBag.Culture == "pt-BR" ? "Tutoriais QR Code" : "Tutoriales Código QR";
|
||||
var isEn = (ViewBag.Culture as string) == "en";
|
||||
var isEs = (ViewBag.Culture as string) == "es-PY" || (ViewBag.Culture as string) == "es";
|
||||
string T(string pt, string es, string en) => isEn ? en : isEs ? es : pt;
|
||||
|
||||
ViewData["Title"] = T("Tutoriais QR Code", "Tutoriales Código QR", "QR Code Tutorials");
|
||||
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||
}
|
||||
|
||||
@ -10,12 +14,12 @@
|
||||
<div class="col-12">
|
||||
<h1 class="display-4">
|
||||
<i class="fas fa-book"></i>
|
||||
@(ViewBag.Culture == "pt-BR" ? "Tutoriais QR Code" : "Tutoriales Código QR")
|
||||
@T("Tutoriais QR Code", "Tutoriales Código QR", "QR Code Tutorials")
|
||||
</h1>
|
||||
<p class="lead text-muted">
|
||||
@(ViewBag.Culture == "pt-BR"
|
||||
? "Aprenda tudo sobre QR Codes com nossos tutoriais completos e passo a passo"
|
||||
: "Aprende todo sobre códigos QR con nuestros tutoriales completos paso a paso")
|
||||
@T("Aprenda tudo sobre QR Codes com nossos tutoriais completos e passo a passo",
|
||||
"Aprende todo sobre códigos QR con nuestros tutoriales completos paso a paso",
|
||||
"Learn everything about QR Codes with our complete step-by-step tutorials")
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -45,7 +49,7 @@
|
||||
|
||||
<a href="/@ViewBag.Culture/tutoriais/@article.Slug"
|
||||
class="btn btn-primary btn-block">
|
||||
@(ViewBag.Culture == "pt-BR" ? "Ler Tutorial" : "Leer Tutorial")
|
||||
@T("Ler Tutorial", "Leer Tutorial", "Read Tutorial")
|
||||
<i class="fas fa-arrow-right ml-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
@ -58,9 +62,9 @@
|
||||
{
|
||||
<div class="alert alert-info" role="alert">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
@(ViewBag.Culture == "pt-BR"
|
||||
? "Nenhum tutorial disponível no momento. Volte em breve!"
|
||||
: "No hay tutoriales disponibles en este momento. ¡Vuelve pronto!")
|
||||
@T("Nenhum tutorial disponível no momento. Volte em breve!",
|
||||
"No hay tutoriales disponibles en este momento. ¡Vuelve pronto!",
|
||||
"No tutorials available at the moment. Check back soon!")
|
||||
</div>
|
||||
}
|
||||
|
||||
@ -70,18 +74,18 @@
|
||||
<div class="card bg-primary text-white">
|
||||
<div class="card-body text-center py-5">
|
||||
<h3 class="mb-3">
|
||||
@(ViewBag.Culture == "pt-BR"
|
||||
? "Pronto para criar seu QR Code?"
|
||||
: "¿Listo para crear tu código QR?")
|
||||
@T("Pronto para criar seu QR Code?",
|
||||
"¿Listo para crear tu código QR?",
|
||||
"Ready to create your QR Code?")
|
||||
</h3>
|
||||
<p class="lead mb-4">
|
||||
@(ViewBag.Culture == "pt-BR"
|
||||
? "Gere QR codes profissionais em segundos com nossa ferramenta ultrarrápida!"
|
||||
: "¡Genera códigos QR profesionales en segundos con nuestra herramienta ultrarrápida!")
|
||||
@T("Gere QR codes profissionais em segundos com nossa ferramenta ultrarrápida!",
|
||||
"¡Genera códigos QR profesionales en segundos con nuestra herramienta ultrarrápida!",
|
||||
"Generate professional QR codes in seconds with our ultra-fast tool!")
|
||||
</p>
|
||||
<a href="/@ViewBag.Culture" class="btn btn-light btn-lg">
|
||||
<i class="fas fa-qrcode"></i>
|
||||
@(ViewBag.Culture == "pt-BR" ? "Criar QR Code Agora" : "Crear Código QR Ahora")
|
||||
@T("Criar QR Code Agora", "Crear Código QR Ahora", "Create QR Code Now")
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -2,31 +2,33 @@
|
||||
// SEO Strategy:
|
||||
// - Portuguese (pt-BR): URLs without prefix (/, /pix, /wifi, etc.) - canonical
|
||||
// - Spanish (es-PY): URLs with /es-PY prefix (/es-PY, /es-PY/pix, etc.)
|
||||
// - English (en): URLs with /en prefix (/en, /en/pix, etc.)
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const languageDropdownItems = document.querySelectorAll('.dropdown-item[data-lang]');
|
||||
const currentLangSpan = document.getElementById('current-lang');
|
||||
|
||||
// Cultures that use a URL prefix
|
||||
const prefixedCultures = ['es-PY', 'en'];
|
||||
|
||||
// Get current culture from URL
|
||||
function getCurrentCulture() {
|
||||
const pathSegments = window.location.pathname.split('/').filter(segment => segment);
|
||||
|
||||
// Check if first segment is es-PY (Spanish)
|
||||
if (pathSegments.length > 0 && pathSegments[0].toLowerCase() === 'es-py') {
|
||||
return 'es-PY';
|
||||
if (pathSegments.length > 0) {
|
||||
const first = pathSegments[0].toLowerCase();
|
||||
if (first === 'es-py') return 'es-PY';
|
||||
if (first === 'en') return 'en';
|
||||
}
|
||||
|
||||
// Default is Portuguese (no prefix in URL)
|
||||
return 'pt-BR';
|
||||
return 'pt-BR'; // Default — no prefix
|
||||
}
|
||||
|
||||
// Update current language display in header
|
||||
function updateCurrentLanguageDisplay(culture) {
|
||||
const langMap = {
|
||||
'pt-BR': 'PT',
|
||||
'es-PY': 'ES'
|
||||
'es-PY': 'ES',
|
||||
'en': 'EN'
|
||||
};
|
||||
|
||||
if (currentLangSpan) {
|
||||
currentLangSpan.textContent = langMap[culture] || 'PT';
|
||||
}
|
||||
@ -35,28 +37,27 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
// Build new URL with selected culture
|
||||
function buildLocalizedUrl(newCulture) {
|
||||
const currentPath = window.location.pathname;
|
||||
const queryString = window.location.search;
|
||||
const hash = window.location.hash;
|
||||
const queryString = window.location.search;
|
||||
const hash = window.location.hash;
|
||||
|
||||
// Get path segments, removing any culture prefix
|
||||
// Strip any existing culture prefix
|
||||
let pathSegments = currentPath.split('/').filter(segment => segment);
|
||||
|
||||
// Remove existing culture prefix if present (es-PY or pt-BR)
|
||||
if (pathSegments.length > 0) {
|
||||
const firstSegment = pathSegments[0].toLowerCase();
|
||||
if (firstSegment === 'es-py' || firstSegment === 'pt-br') {
|
||||
const first = pathSegments[0].toLowerCase();
|
||||
if (first === 'es-py' || first === 'pt-br' || first === 'en') {
|
||||
pathSegments.shift();
|
||||
}
|
||||
}
|
||||
|
||||
// Build new path based on selected culture
|
||||
const rest = pathSegments.length > 0 ? '/' + pathSegments.join('/') : '';
|
||||
|
||||
let newPath;
|
||||
if (newCulture === 'pt-BR') {
|
||||
// Portuguese: no prefix (canonical URLs)
|
||||
newPath = pathSegments.length > 0 ? '/' + pathSegments.join('/') : '/';
|
||||
newPath = rest || '/';
|
||||
} else {
|
||||
// Spanish: add /es-PY prefix
|
||||
newPath = '/es-PY' + (pathSegments.length > 0 ? '/' + pathSegments.join('/') : '');
|
||||
// Spanish / English: add culture prefix
|
||||
newPath = '/' + newCulture + rest;
|
||||
}
|
||||
|
||||
return newPath + queryString + hash;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user